2957 lines · plain
1; RUN: opt -aa-pipeline=basic-aa -passes=objc-arc -S < %s | FileCheck %s2 3target datalayout = "e-p:64:64:64"4 5declare ptr @llvm.objc.retain(ptr)6declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)7declare ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr)8declare void @llvm.objc.release(ptr)9declare ptr @llvm.objc.autorelease(ptr)10declare ptr @llvm.objc.autoreleaseReturnValue(ptr)11declare void @llvm.objc.autoreleasePoolPop(ptr)12declare ptr @llvm.objc.autoreleasePoolPush()13declare ptr @llvm.objc.retainBlock(ptr)14 15declare ptr @llvm.objc.retainedObject(ptr)16declare ptr @llvm.objc.unretainedObject(ptr)17declare ptr @llvm.objc.unretainedPointer(ptr)18 19declare void @use_pointer(ptr)20declare void @callee()21declare void @callee2(ptr, ptr)22declare void @callee_fnptr(ptr)23declare void @invokee()24declare ptr @returner()25declare void @bar(ptr)26 27declare void @llvm.dbg.value(metadata, metadata, metadata)28 29declare ptr @objc_msgSend(ptr, ptr, ...)30 31; Simple retain+release pair deletion, with some intervening control32; flow and harmless instructions.33 34; CHECK: define void @test0_precise(ptr %x, i1 %p) [[NUW:#[0-9]+]] {35; CHECK: @llvm.objc.retain36; CHECK: @llvm.objc.release37; CHECK: {{^}}}38define void @test0_precise(ptr %x, i1 %p) nounwind {39entry:40 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind41 br i1 %p, label %t, label %f42 43t:44 store i8 3, ptr %x45 store float 2.0, ptr %x46 br label %return47 48f:49 store i32 7, ptr %x50 br label %return51 52return:53 call void @llvm.objc.release(ptr %x) nounwind54 ret void55}56 57; CHECK: define void @test0_imprecise(ptr %x, i1 %p) [[NUW]] {58; CHECK-NOT: @llvm.objc.59; CHECK: {{^}}}60define void @test0_imprecise(ptr %x, i1 %p) nounwind {61entry:62 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind63 br i1 %p, label %t, label %f64 65t:66 store i8 3, ptr %x67 store float 2.0, ptr %x68 br label %return69 70f:71 store i32 7, ptr %x72 br label %return73 74return:75 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !076 ret void77}78 79; Like test0 but the release isn't always executed when the retain is,80; so the optimization is not safe.81 82; TODO: Make the llvm.objc.release's argument be %0.83 84; CHECK: define void @test1_precise(ptr %x, i1 %p, i1 %q) [[NUW]] {85; CHECK: @llvm.objc.retain(ptr %x)86; CHECK: @llvm.objc.release(ptr %x)87; CHECK: {{^}}}88define void @test1_precise(ptr %x, i1 %p, i1 %q) nounwind {89entry:90 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind91 br i1 %p, label %t, label %f92 93t:94 store i8 3, ptr %x95 store float 2.0, ptr %x96 br label %return97 98f:99 store i32 7, ptr %x100 call void @callee()101 br i1 %q, label %return, label %alt_return102 103return:104 call void @llvm.objc.release(ptr %x) nounwind105 ret void106 107alt_return:108 ret void109}110 111; CHECK: define void @test1_imprecise(ptr %x, i1 %p, i1 %q) [[NUW]] {112; CHECK: @llvm.objc.retain(ptr %x)113; CHECK: @llvm.objc.release114; CHECK: {{^}}}115define void @test1_imprecise(ptr %x, i1 %p, i1 %q) nounwind {116entry:117 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind118 br i1 %p, label %t, label %f119 120t:121 store i8 3, ptr %x122 store float 2.0, ptr %x123 br label %return124 125f:126 store i32 7, ptr %x127 call void @callee()128 br i1 %q, label %return, label %alt_return129 130return:131 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0132 ret void133 134alt_return:135 ret void136}137 138 139; Don't do partial elimination into two different CFG diamonds.140 141; CHECK: define void @test1b_precise(ptr %x, i1 %p, i1 %q) {142; CHECK: entry:143; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]144; CHECK-NOT: @llvm.objc.145; CHECK: if.end5:146; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]]147; CHECK-NOT: @llvm.objc.148; CHECK: {{^}}}149define void @test1b_precise(ptr %x, i1 %p, i1 %q) {150entry:151 tail call ptr @llvm.objc.retain(ptr %x) nounwind152 br i1 %p, label %if.then, label %if.end153 154if.then: ; preds = %entry155 tail call void @callee()156 br label %if.end157 158if.end: ; preds = %if.then, %entry159 br i1 %q, label %if.then3, label %if.end5160 161if.then3: ; preds = %if.end162 tail call void @use_pointer(ptr %x)163 br label %if.end5164 165if.end5: ; preds = %if.then3, %if.end166 tail call void @llvm.objc.release(ptr %x) nounwind167 ret void168}169 170; CHECK-LABEL: define void @test1b_imprecise(171; CHECK: entry:172; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW:#[0-9]+]]173; CHECK-NOT: @llvm.objc.174; CHECK: if.end5:175; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]], !clang.imprecise_release ![[RELEASE:[0-9]+]]176; CHECK-NOT: @llvm.objc.177; CHECK: {{^}}}178define void @test1b_imprecise(ptr %x, i1 %p, i1 %q) {179entry:180 tail call ptr @llvm.objc.retain(ptr %x) nounwind181 br i1 %p, label %if.then, label %if.end182 183if.then: ; preds = %entry184 tail call void @callee()185 br label %if.end186 187if.end: ; preds = %if.then, %entry188 br i1 %q, label %if.then3, label %if.end5189 190if.then3: ; preds = %if.end191 tail call void @use_pointer(ptr %x)192 br label %if.end5193 194if.end5: ; preds = %if.then3, %if.end195 tail call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0196 ret void197}198 199 200; Like test0 but the pointer is passed to an intervening call,201; so the optimization is not safe.202 203; CHECK-LABEL: define void @test2_precise(204; CHECK: @llvm.objc.retain(ptr %x)205; CHECK: @llvm.objc.release206; CHECK: {{^}}}207define void @test2_precise(ptr %x, i1 %p) nounwind {208entry:209 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind210 br i1 %p, label %t, label %f211 212t:213 store i8 3, ptr %x214 store float 2.0, ptr %x215 br label %return216 217f:218 store i32 7, ptr %x219 call void @use_pointer(ptr %0)220 store float 3.0, ptr %x221 br label %return222 223return:224 call void @llvm.objc.release(ptr %x) nounwind225 ret void226}227 228; CHECK-LABEL: define void @test2_imprecise(229; CHECK: @llvm.objc.retain(ptr %x)230; CHECK: @llvm.objc.release231; CHECK: {{^}}}232define void @test2_imprecise(ptr %x, i1 %p) nounwind {233entry:234 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind235 br i1 %p, label %t, label %f236 237t:238 store i8 3, ptr %x239 store float 2.0, ptr %x240 br label %return241 242f:243 store i32 7, ptr %x244 call void @use_pointer(ptr %0)245 store float 3.0, ptr %x246 br label %return247 248return:249 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0250 ret void251}252 253; Like test0 but the release is in a loop,254; so the optimization is not safe.255 256; TODO: For now, assume this can't happen.257 258; CHECK-LABEL: define void @test3_precise(259; TODO: @llvm.objc.retain(ptr %a)260; TODO: @llvm.objc.release261; CHECK: {{^}}}262define void @test3_precise(ptr %x, ptr %q) nounwind {263entry:264 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind265 br label %loop266 267loop:268 call void @llvm.objc.release(ptr %x) nounwind269 %j = load volatile i1, ptr %q270 br i1 %j, label %loop, label %return271 272return:273 ret void274}275 276; CHECK-LABEL: define void @test3_imprecise(277; TODO: @llvm.objc.retain(ptr %a)278; TODO: @llvm.objc.release279; CHECK: {{^}}}280define void @test3_imprecise(ptr %x, ptr %q) nounwind {281entry:282 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind283 br label %loop284 285loop:286 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0287 %j = load volatile i1, ptr %q288 br i1 %j, label %loop, label %return289 290return:291 ret void292}293 294 295; TODO: For now, assume this can't happen.296 297; Like test0 but the retain is in a loop,298; so the optimization is not safe.299 300; CHECK-LABEL: define void @test4_precise(301; TODO: @llvm.objc.retain(ptr %a)302; TODO: @llvm.objc.release303; CHECK: {{^}}}304define void @test4_precise(ptr %x, ptr %q) nounwind {305entry:306 br label %loop307 308loop:309 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind310 %j = load volatile i1, ptr %q311 br i1 %j, label %loop, label %return312 313return:314 call void @llvm.objc.release(ptr %x) nounwind315 ret void316}317 318; CHECK-LABEL: define void @test4_imprecise(319; TODO: @llvm.objc.retain(ptr %a)320; TODO: @llvm.objc.release321; CHECK: {{^}}}322define void @test4_imprecise(ptr %x, ptr %q) nounwind {323entry:324 br label %loop325 326loop:327 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind328 %j = load volatile i1, ptr %q329 br i1 %j, label %loop, label %return330 331return:332 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0333 ret void334}335 336 337; Like test0 but the pointer is conditionally passed to an intervening call,338; so the optimization is not safe.339 340; CHECK-LABEL: define void @test5a(341; CHECK: @llvm.objc.retain(ptr342; CHECK: @llvm.objc.release343; CHECK: {{^}}}344define void @test5a(ptr %x, i1 %q, ptr %y) nounwind {345entry:346 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind347 %s = select i1 %q, ptr %y, ptr %0348 call void @use_pointer(ptr %s)349 store i32 7, ptr %x350 call void @llvm.objc.release(ptr %x) nounwind351 ret void352}353 354; CHECK-LABEL: define void @test5b(355; CHECK: @llvm.objc.retain(ptr356; CHECK: @llvm.objc.release357; CHECK: {{^}}}358define void @test5b(ptr %x, i1 %q, ptr %y) nounwind {359entry:360 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind361 %s = select i1 %q, ptr %y, ptr %0362 call void @use_pointer(ptr %s)363 store i32 7, ptr %x364 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0365 ret void366}367 368 369; retain+release pair deletion, where the release happens on two different370; flow paths.371 372; CHECK-LABEL: define void @test6a(373; CHECK: entry:374; CHECK: tail call ptr @llvm.objc.retain375; CHECK: t:376; CHECK: call void @llvm.objc.release377; CHECK: f:378; CHECK: call void @llvm.objc.release379; CHECK: return:380; CHECK: {{^}}}381define void @test6a(ptr %x, i1 %p) nounwind {382entry:383 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind384 br i1 %p, label %t, label %f385 386t:387 store i8 3, ptr %x388 store float 2.0, ptr %x389 call void @llvm.objc.release(ptr %x) nounwind390 br label %return391 392f:393 store i32 7, ptr %x394 call void @callee()395 call void @llvm.objc.release(ptr %x) nounwind396 br label %return397 398return:399 ret void400}401 402; CHECK-LABEL: define void @test6b(403; CHECK-NOT: @llvm.objc.404; CHECK: {{^}}}405define void @test6b(ptr %x, i1 %p) nounwind {406entry:407 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind408 br i1 %p, label %t, label %f409 410t:411 store i8 3, ptr %x412 store float 2.0, ptr %x413 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0414 br label %return415 416f:417 store i32 7, ptr %x418 call void @callee()419 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0420 br label %return421 422return:423 ret void424}425 426; CHECK-LABEL: define void @test6c(427; CHECK: entry:428; CHECK: tail call ptr @llvm.objc.retain429; CHECK: t:430; CHECK: call void @llvm.objc.release431; CHECK: f:432; CHECK: call void @llvm.objc.release433; CHECK: return:434; CHECK: {{^}}}435define void @test6c(ptr %x, i1 %p) nounwind {436entry:437 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind438 br i1 %p, label %t, label %f439 440t:441 store i8 3, ptr %x442 store float 2.0, ptr %x443 call void @llvm.objc.release(ptr %x) nounwind444 br label %return445 446f:447 store i32 7, ptr %x448 call void @callee()449 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0450 br label %return451 452return:453 ret void454}455 456; CHECK-LABEL: define void @test6d(457; CHECK: entry:458; CHECK: tail call ptr @llvm.objc.retain459; CHECK: t:460; CHECK: call void @llvm.objc.release461; CHECK: f:462; CHECK: call void @llvm.objc.release463; CHECK: return:464; CHECK: {{^}}}465define void @test6d(ptr %x, i1 %p) nounwind {466entry:467 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind468 br i1 %p, label %t, label %f469 470t:471 store i8 3, ptr %x472 store float 2.0, ptr %x473 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0474 br label %return475 476f:477 store i32 7, ptr %x478 call void @callee()479 call void @llvm.objc.release(ptr %x) nounwind480 br label %return481 482return:483 ret void484}485 486 487; retain+release pair deletion, where the retain happens on two different488; flow paths.489 490; CHECK-LABEL: define void @test7(491; CHECK: entry:492; CHECK-NOT: llvm.objc.493; CHECK: t:494; CHECK: call ptr @llvm.objc.retain495; CHECK: f:496; CHECK: call ptr @llvm.objc.retain497; CHECK: return:498; CHECK: call void @llvm.objc.release499; CHECK: {{^}}}500define void @test7(ptr %x, i1 %p) nounwind {501entry:502 br i1 %p, label %t, label %f503 504t:505 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind506 store i8 3, ptr %x507 store float 2.0, ptr %x508 br label %return509 510f:511 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind512 store i32 7, ptr %x513 call void @callee()514 br label %return515 516return:517 call void @llvm.objc.release(ptr %x) nounwind518 ret void519}520 521; CHECK-LABEL: define void @test7b(522; CHECK-NOT: @llvm.objc.523; CHECK: {{^}}}524define void @test7b(ptr %x, i1 %p) nounwind {525entry:526 br i1 %p, label %t, label %f527 528t:529 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind530 store i8 3, ptr %x531 store float 2.0, ptr %x532 br label %return533 534f:535 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind536 store i32 7, ptr %x537 call void @callee()538 br label %return539 540return:541 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0542 ret void543}544 545; Like test7, but there's a retain/retainBlock mismatch. Don't delete!546 547; CHECK-LABEL: define void @test7c(548; CHECK: t:549; CHECK: call ptr @llvm.objc.retainBlock550; CHECK: f:551; CHECK: call ptr @llvm.objc.retain552; CHECK: return:553; CHECK: call void @llvm.objc.release554; CHECK: {{^}}}555define void @test7c(ptr %x, i1 %p) nounwind {556entry:557 br i1 %p, label %t, label %f558 559t:560 %0 = call ptr @llvm.objc.retainBlock(ptr %x) nounwind561 store i8 3, ptr %x562 store float 2.0, ptr %x563 br label %return564 565f:566 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind567 store i32 7, ptr %x568 call void @callee()569 br label %return570 571return:572 call void @llvm.objc.release(ptr %x) nounwind573 ret void574}575 576; retain+release pair deletion, where the retain and release both happen on577; different flow paths. Wild!578 579; CHECK-LABEL: define void @test8a(580; CHECK: entry:581; CHECK: t:582; CHECK: @llvm.objc.retain583; CHECK: f:584; CHECK: @llvm.objc.retain585; CHECK: mid:586; CHECK: u:587; CHECK: @llvm.objc.release588; CHECK: g:589; CHECK: @llvm.objc.release590; CHECK: return:591; CHECK: {{^}}}592define void @test8a(ptr %x, i1 %p, i1 %q) nounwind {593entry:594 br i1 %p, label %t, label %f595 596t:597 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind598 store i8 3, ptr %x599 store float 2.0, ptr %x600 br label %mid601 602f:603 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind604 store i32 7, ptr %x605 br label %mid606 607mid:608 br i1 %q, label %u, label %g609 610u:611 call void @callee()612 call void @llvm.objc.release(ptr %x) nounwind613 br label %return614 615g:616 call void @llvm.objc.release(ptr %x) nounwind617 br label %return618 619return:620 ret void621}622 623; CHECK-LABEL: define void @test8b(624; CHECK-NOT: @llvm.objc.625; CHECK: {{^}}}626define void @test8b(ptr %x, i1 %p, i1 %q) nounwind {627entry:628 br i1 %p, label %t, label %f629 630t:631 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind632 store i8 3, ptr %x633 store float 2.0, ptr %x634 br label %mid635 636f:637 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind638 store i32 7, ptr %x639 br label %mid640 641mid:642 br i1 %q, label %u, label %g643 644u:645 call void @callee()646 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0647 br label %return648 649g:650 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0651 br label %return652 653return:654 ret void655}656 657; CHECK-LABEL: define void @test8c(658; CHECK: entry:659; CHECK: t:660; CHECK-NOT: @llvm.objc.661; CHECK: f:662; CHECK-NOT: @llvm.objc.663; CHECK: mid:664; CHECK: u:665; CHECK: @llvm.objc.retain666; CHECK: @llvm.objc.release667; CHECK: g:668; CHECK-NOT: @llvm.objc.669; CHECK: return:670; CHECK: {{^}}}671define void @test8c(ptr %x, i1 %p, i1 %q) nounwind {672entry:673 br i1 %p, label %t, label %f674 675t:676 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind677 store i8 3, ptr %x678 store float 2.0, ptr %x679 br label %mid680 681f:682 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind683 store i32 7, ptr %x684 br label %mid685 686mid:687 br i1 %q, label %u, label %g688 689u:690 call void @callee()691 call void @llvm.objc.release(ptr %x) nounwind692 br label %return693 694g:695 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0696 br label %return697 698return:699 ret void700}701 702; CHECK-LABEL: define void @test8d(703; CHECK: entry:704; CHECK: t:705; CHECK: @llvm.objc.retain706; CHECK: f:707; CHECK: @llvm.objc.retain708; CHECK: mid:709; CHECK: u:710; CHECK: @llvm.objc.release711; CHECK: g:712; CHECK: @llvm.objc.release713; CHECK: return:714; CHECK: {{^}}}715define void @test8d(ptr %x, i1 %p, i1 %q) nounwind {716entry:717 br i1 %p, label %t, label %f718 719t:720 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind721 store i8 3, ptr %x722 store float 2.0, ptr %x723 br label %mid724 725f:726 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind727 store i32 7, ptr %x728 br label %mid729 730mid:731 br i1 %q, label %u, label %g732 733u:734 call void @callee()735 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0736 br label %return737 738g:739 call void @llvm.objc.release(ptr %x) nounwind740 br label %return741 742return:743 ret void744}745 746; Trivial retain+release pair deletion.747 748; CHECK-LABEL: define void @test9(749; CHECK-NOT: @llvm.objc.750; CHECK: {{^}}}751define void @test9(ptr %x) nounwind {752entry:753 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind754 call void @llvm.objc.release(ptr %0) nounwind755 ret void756}757 758; Retain+release pair, but on an unknown pointer relationship. Don't delete!759 760; CHECK-LABEL: define void @test9b(761; CHECK: @llvm.objc.retain(ptr %x)762; CHECK: @llvm.objc.release(ptr %s)763; CHECK: {{^}}}764define void @test9b(ptr %x, i1 %j, ptr %p) nounwind {765entry:766 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind767 %s = select i1 %j, ptr %x, ptr %p768 call void @llvm.objc.release(ptr %s) nounwind769 ret void770}771 772; Trivial retain+release pair with intervening calls - don't delete!773 774; CHECK-LABEL: define void @test10(775; CHECK: @llvm.objc.retain(ptr %x)776; CHECK: @callee777; CHECK: @use_pointer778; CHECK: @llvm.objc.release779; CHECK: {{^}}}780define void @test10(ptr %x) nounwind {781entry:782 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind783 call void @callee()784 call void @use_pointer(ptr %x)785 call void @llvm.objc.release(ptr %0) nounwind786 ret void787}788 789; Trivial retain+autoreleaserelease pair. Don't delete!790; Also, add a tail keyword, since llvm.objc.retain can never be passed791; a stack argument.792 793; CHECK-LABEL: define void @test11(794; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]795; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]]796; CHECK: {{^}}}797define void @test11(ptr %x) nounwind {798entry:799 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind800 call ptr @llvm.objc.autorelease(ptr %0) nounwind801 call void @use_pointer(ptr %x)802 ret void803}804 805; Same as test11 but with no use_pointer call. Delete the pair!806 807; CHECK-LABEL: define void @test11a(808; CHECK: entry:809; CHECK-NEXT: ret void810; CHECK: {{^}}}811define void @test11a(ptr %x) nounwind {812entry:813 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind814 call ptr @llvm.objc.autorelease(ptr %0) nounwind815 ret void816}817 818; Same as test11 but the value is returned. Do not perform an RV optimization819; since if the frontend emitted code for an __autoreleasing variable, we may820; want it to be in the autorelease pool.821 822; CHECK-LABEL: define ptr @test11b(823; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]824; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]]825; CHECK: {{^}}}826define ptr @test11b(ptr %x) nounwind {827entry:828 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind829 call ptr @llvm.objc.autorelease(ptr %0) nounwind830 ret ptr %x831}832 833; We can not delete this retain, release since we do not have a post-dominating834; use of the release.835 836; CHECK-LABEL: define void @test12(837; CHECK-NEXT: entry:838; CHECK-NEXT: @llvm.objc.retain(ptr %x)839; CHECK-NEXT: @llvm.objc.retain840; CHECK: @llvm.objc.release841; CHECK: {{^}}}842define void @test12(ptr %x, i64 %n) {843entry:844 call ptr @llvm.objc.retain(ptr %x) nounwind845 call ptr @llvm.objc.retain(ptr %x) nounwind846 call void @use_pointer(ptr %x)847 call void @use_pointer(ptr %x)848 call void @llvm.objc.release(ptr %x) nounwind849 ret void850}851 852; Trivial retain,autorelease pair. Don't delete!853 854; CHECK-LABEL: define void @test13(855; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]856; CHECK: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]857; CHECK: @use_pointer(ptr %x)858; CHECK: call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]859; CHECK: {{^}}}860define void @test13(ptr %x, i64 %n) {861entry:862 call ptr @llvm.objc.retain(ptr %x) nounwind863 call ptr @llvm.objc.retain(ptr %x) nounwind864 call void @use_pointer(ptr %x)865 call ptr @llvm.objc.autorelease(ptr %x) nounwind866 ret void867}868 869; Delete the retain+release pair.870 871; CHECK-LABEL: define void @test13b(872; CHECK-NEXT: entry:873; CHECK-NEXT: @llvm.objc.retain(ptr %x)874; CHECK-NEXT: @use_pointer875; CHECK-NEXT: @use_pointer876; CHECK-NEXT: @use_pointer877; CHECK-NEXT: @llvm.objc.release878; CHECK-NEXT: ret void879; CHECK-NEXT: }880define void @test13b(ptr %x, i64 %n) {881entry:882 call ptr @llvm.objc.retain(ptr %x) nounwind883 call ptr @llvm.objc.retain(ptr %x) nounwind884 call void @use_pointer(ptr %x)885 call void @use_pointer(ptr %x)886 call void @llvm.objc.release(ptr %x) nounwind887 call void @use_pointer(ptr %x)888 call void @llvm.objc.release(ptr %x) nounwind889 ret void890}891 892; Don't delete the retain+release pair because there's an893; autoreleasePoolPop in the way.894 895; CHECK-LABEL: define void @test13c(896; CHECK: @llvm.objc.retain(ptr %x)897; CHECK: @llvm.objc.autoreleasePoolPop898; CHECK: @llvm.objc.retain(ptr %x)899; CHECK: @use_pointer900; CHECK: @llvm.objc.release901; CHECK: {{^}}}902define void @test13c(ptr %x, i64 %n) {903entry:904 call ptr @llvm.objc.retain(ptr %x) nounwind905 call void @llvm.objc.autoreleasePoolPop(ptr undef)906 call ptr @llvm.objc.retain(ptr %x) nounwind907 call void @use_pointer(ptr %x)908 call void @use_pointer(ptr %x)909 call void @llvm.objc.release(ptr %x) nounwind910 ret void911}912 913; Like test13c, but there's an autoreleasePoolPush in the way, but that914; doesn't matter.915 916; CHECK-LABEL: define void @test13d(917; CHECK-NEXT: entry:918; CHECK-NEXT: @llvm.objc.retain(ptr %x)919; CHECK-NEXT: @llvm.objc.autoreleasePoolPush920; CHECK-NEXT: @use_pointer921; CHECK-NEXT: @use_pointer922; CHECK-NEXT: @use_pointer923; CHECK-NEXT: @llvm.objc.release924; CHECK-NEXT: ret void925; CHECK-NEXT: }926define void @test13d(ptr %x, i64 %n) {927entry:928 call ptr @llvm.objc.retain(ptr %x) nounwind929 call ptr @llvm.objc.autoreleasePoolPush()930 call ptr @llvm.objc.retain(ptr %x) nounwind931 call void @use_pointer(ptr %x)932 call void @use_pointer(ptr %x)933 call void @llvm.objc.release(ptr %x) nounwind934 call void @use_pointer(ptr %x)935 call void @llvm.objc.release(ptr %x) nounwind936 ret void937}938 939; Trivial retain,release pair with intervening call, and it's post-dominated by940; another release. But it is not known safe in the top down direction. We can941; not eliminate it.942 943; CHECK-LABEL: define void @test14(944; CHECK-NEXT: entry:945; CHECK-NEXT: @llvm.objc.retain946; CHECK-NEXT: @use_pointer947; CHECK-NEXT: @use_pointer948; CHECK-NEXT: @llvm.objc.release949; CHECK-NEXT: @llvm.objc.release950; CHECK-NEXT: ret void951; CHECK-NEXT: }952define void @test14(ptr %x, i64 %n) {953entry:954 call ptr @llvm.objc.retain(ptr %x) nounwind955 call void @use_pointer(ptr %x)956 call void @use_pointer(ptr %x)957 call void @llvm.objc.release(ptr %x) nounwind958 call void @llvm.objc.release(ptr %x) nounwind959 ret void960}961 962; Trivial retain,autorelease pair with intervening call, but it's post-dominated963; by another release. Don't delete anything.964 965; CHECK-LABEL: define void @test15(966; CHECK-NEXT: entry:967; CHECK-NEXT: @llvm.objc.retain(ptr %x)968; CHECK-NEXT: @use_pointer969; CHECK-NEXT: @llvm.objc.autorelease(ptr %x)970; CHECK-NEXT: @llvm.objc.release971; CHECK-NEXT: ret void972; CHECK-NEXT: }973define void @test15(ptr %x, i64 %n) {974entry:975 call ptr @llvm.objc.retain(ptr %x) nounwind976 call void @use_pointer(ptr %x)977 call ptr @llvm.objc.autorelease(ptr %x) nounwind978 call void @llvm.objc.release(ptr %x) nounwind979 ret void980}981 982; Trivial retain,autorelease pair, post-dominated983; by another release. Delete the retain and release.984 985; CHECK-LABEL: define void @test15b(986; CHECK-NEXT: entry:987; CHECK-NEXT: @llvm.objc.retain988; CHECK-NEXT: @llvm.objc.autorelease989; CHECK-NEXT: @llvm.objc.release990; CHECK-NEXT: ret void991; CHECK-NEXT: }992define void @test15b(ptr %x, i64 %n) {993entry:994 call ptr @llvm.objc.retain(ptr %x) nounwind995 call ptr @llvm.objc.autorelease(ptr %x) nounwind996 call void @llvm.objc.release(ptr %x) nounwind997 ret void998}999 1000; CHECK-LABEL: define void @test15c(1001; CHECK-NEXT: entry:1002; CHECK-NEXT: @llvm.objc.autorelease1003; CHECK-NEXT: ret void1004; CHECK-NEXT: }1005define void @test15c(ptr %x, i64 %n) {1006entry:1007 call ptr @llvm.objc.retain(ptr %x) nounwind1008 call ptr @llvm.objc.autorelease(ptr %x) nounwind1009 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !01010 ret void1011}1012 1013; Retain+release pairs in diamonds, all dominated by a retain.1014 1015; CHECK-LABEL: define void @test16a(1016; CHECK: @llvm.objc.retain(ptr %x)1017; CHECK-NOT: @objc1018; CHECK: purple:1019; CHECK: @use_pointer1020; CHECK: @llvm.objc.release1021; CHECK: {{^}}}1022define void @test16a(i1 %a, i1 %b, ptr %x) {1023entry:1024 call ptr @llvm.objc.retain(ptr %x) nounwind1025 br i1 %a, label %red, label %orange1026 1027red:1028 call ptr @llvm.objc.retain(ptr %x) nounwind1029 br label %yellow1030 1031orange:1032 call ptr @llvm.objc.retain(ptr %x) nounwind1033 br label %yellow1034 1035yellow:1036 call void @use_pointer(ptr %x)1037 call void @use_pointer(ptr %x)1038 br i1 %b, label %green, label %blue1039 1040green:1041 call void @llvm.objc.release(ptr %x) nounwind1042 br label %purple1043 1044blue:1045 call void @llvm.objc.release(ptr %x) nounwind1046 br label %purple1047 1048purple:1049 call void @use_pointer(ptr %x)1050 call void @llvm.objc.release(ptr %x) nounwind1051 ret void1052}1053 1054; CHECK-LABEL: define void @test16b(1055; CHECK: @llvm.objc.retain(ptr %x)1056; CHECK-NOT: @objc1057; CHECK: purple:1058; CHECK-NEXT: @use_pointer1059; CHECK-NEXT: @use_pointer1060; CHECK-NEXT: @llvm.objc.release1061; CHECK: {{^}}}1062define void @test16b(i1 %a, i1 %b, ptr %x) {1063entry:1064 call ptr @llvm.objc.retain(ptr %x) nounwind1065 br i1 %a, label %red, label %orange1066 1067red:1068 call ptr @llvm.objc.retain(ptr %x) nounwind1069 br label %yellow1070 1071orange:1072 call ptr @llvm.objc.retain(ptr %x) nounwind1073 br label %yellow1074 1075yellow:1076 call void @use_pointer(ptr %x)1077 call void @use_pointer(ptr %x)1078 br i1 %b, label %green, label %blue1079 1080green:1081 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !01082 br label %purple1083 1084blue:1085 call void @llvm.objc.release(ptr %x) nounwind1086 br label %purple1087 1088purple:1089 call void @use_pointer(ptr %x)1090 call void @use_pointer(ptr %x)1091 call void @llvm.objc.release(ptr %x) nounwind1092 ret void1093}1094 1095; CHECK-LABEL: define void @test16c(1096; CHECK: @llvm.objc.retain(ptr %x)1097; CHECK-NOT: @objc1098; CHECK: purple:1099; CHECK: @use_pointer1100; CHECK: @llvm.objc.release1101; CHECK: {{^}}}1102define void @test16c(i1 %a, i1 %b, ptr %x) {1103entry:1104 call ptr @llvm.objc.retain(ptr %x) nounwind1105 br i1 %a, label %red, label %orange1106 1107red:1108 call ptr @llvm.objc.retain(ptr %x) nounwind1109 br label %yellow1110 1111orange:1112 call ptr @llvm.objc.retain(ptr %x) nounwind1113 br label %yellow1114 1115yellow:1116 call void @use_pointer(ptr %x)1117 call void @use_pointer(ptr %x)1118 br i1 %b, label %green, label %blue1119 1120green:1121 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !01122 br label %purple1123 1124blue:1125 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !01126 br label %purple1127 1128purple:1129 call void @use_pointer(ptr %x)1130 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !01131 ret void1132}1133 1134; CHECK-LABEL: define void @test16d(1135; CHECK: @llvm.objc.retain(ptr %x)1136; CHECK: @llvm.objc1137; CHECK: {{^}}}1138define void @test16d(i1 %a, i1 %b, ptr %x) {1139entry:1140 call ptr @llvm.objc.retain(ptr %x) nounwind1141 br i1 %a, label %red, label %orange1142 1143red:1144 call ptr @llvm.objc.retain(ptr %x) nounwind1145 br label %yellow1146 1147orange:1148 call ptr @llvm.objc.retain(ptr %x) nounwind1149 br label %yellow1150 1151yellow:1152 call void @use_pointer(ptr %x)1153 call void @use_pointer(ptr %x)1154 br i1 %b, label %green, label %blue1155 1156green:1157 call void @llvm.objc.release(ptr %x) nounwind1158 br label %purple1159 1160blue:1161 call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !01162 br label %purple1163 1164purple:1165 ret void1166}1167 1168; Delete no-ops.1169 1170; CHECK-LABEL: define void @test18(1171; CHECK-NOT: @llvm.objc.1172; CHECK: {{^}}}1173define void @test18() {1174 call ptr @llvm.objc.retain(ptr null)1175 call void @llvm.objc.release(ptr null)1176 call ptr @llvm.objc.autorelease(ptr null)1177 ret void1178}1179 1180; Delete no-ops where undef can be assumed to be null.1181 1182; CHECK-LABEL: define void @test18b(1183; CHECK-NOT: @llvm.objc.1184; CHECK: {{^}}}1185define void @test18b() {1186 call ptr @llvm.objc.retain(ptr undef)1187 call void @llvm.objc.release(ptr undef)1188 call ptr @llvm.objc.autorelease(ptr undef)1189 ret void1190}1191 1192; Replace uses of arguments with uses of return values, to reduce1193; register pressure.1194 1195; CHECK: define void @test19(ptr %y) {1196; CHECK: %0 = tail call ptr @llvm.objc.retain(ptr %y)1197; CHECK: call void @use_pointer(ptr %y)1198; CHECK: call void @use_pointer(ptr %y)1199; CHECK: call void @llvm.objc.release(ptr %y)1200; CHECK: ret void1201; CHECK: {{^}}}1202define void @test19(ptr %y) {1203entry:1204 %0 = call ptr @llvm.objc.retain(ptr %y) nounwind1205 call void @use_pointer(ptr %y)1206 call void @use_pointer(ptr %y)1207 call void @llvm.objc.release(ptr %y)1208 ret void1209}1210 1211; Bitcast insertion1212 1213; CHECK-LABEL: define void @test20(1214; CHECK: %tmp1 = tail call ptr @llvm.objc.retain(ptr %self) [[NUW]]1215; CHECK-NEXT: invoke1216; CHECK: {{^}}}1217define void @test20(ptr %self) personality ptr @__gxx_personality_v0 {1218if.then12:1219 %tmp1 = call ptr @llvm.objc.retain(ptr %self) nounwind1220 invoke void @invokee()1221 to label %invoke.cont23 unwind label %lpad201222 1223invoke.cont23: ; preds = %if.then121224 invoke void @invokee()1225 to label %if.end unwind label %lpad201226 1227lpad20: ; preds = %invoke.cont23, %if.then121228 %tmp502 = phi ptr [ undef, %invoke.cont23 ], [ %self, %if.then12 ]1229 %exn = landingpad {ptr, i32}1230 cleanup1231 unreachable1232 1233if.end: ; preds = %invoke.cont231234 ret void1235}1236 1237; Delete a redundant retain,autorelease when forwaring a call result1238; directly to a return value.1239 1240; CHECK-LABEL: define ptr @test21(1241; CHECK: call ptr @returner()1242; CHECK-NEXT: ret ptr %call1243; CHECK-NEXT: }1244define ptr @test21() {1245entry:1246 %call = call ptr @returner()1247 %0 = call ptr @llvm.objc.retain(ptr %call) nounwind1248 %1 = call ptr @llvm.objc.autorelease(ptr %0) nounwind1249 ret ptr %11250}1251 1252; Move an objc call up through a phi that has null operands.1253 1254; CHECK-LABEL: define void @test22(1255; CHECK: B:1256; CHECK: call void @llvm.objc.release(ptr %p)1257; CHECK: br label %C1258; CHECK: C: ; preds = %B, %A1259; CHECK-NOT: @llvm.objc.release1260; CHECK: {{^}}}1261define void @test22(ptr %p, i1 %a) {1262 br i1 %a, label %A, label %B1263A:1264 br label %C1265B:1266 br label %C1267C:1268 %h = phi ptr [ null, %A ], [ %p, %B ]1269 call void @llvm.objc.release(ptr %h), !clang.imprecise_release !01270 ret void1271}1272 1273; Do not move an llvm.objc.release that doesn't have the clang.imprecise_release tag.1274 1275; CHECK-LABEL: define void @test22_precise(1276; CHECK: %[[P0:.*]] = phi ptr1277; CHECK: call void @llvm.objc.release(ptr %[[P0]])1278; CHECK: ret void1279define void @test22_precise(ptr %p, i1 %a) {1280 br i1 %a, label %A, label %B1281A:1282 br label %C1283B:1284 br label %C1285C:1286 %h = phi ptr [ null, %A ], [ %p, %B ]1287 call void @llvm.objc.release(ptr %h)1288 ret void1289}1290 1291; Any call can decrement a retain count.1292 1293; CHECK-LABEL: define void @test24(1294; CHECK: @llvm.objc.retain(ptr %a)1295; CHECK: @llvm.objc.release1296; CHECK: {{^}}}1297define void @test24(ptr %r, ptr %a) {1298 call ptr @llvm.objc.retain(ptr %a)1299 call void @use_pointer(ptr %r)1300 %q = load i8, ptr %a1301 call void @llvm.objc.release(ptr %a)1302 ret void1303}1304 1305; Don't move a retain/release pair if the release can be moved1306; but the retain can't be moved to balance it.1307 1308; CHECK-LABEL: define void @test25(1309; CHECK: entry:1310; CHECK: call ptr @llvm.objc.retain(ptr %p)1311; CHECK: true:1312; CHECK: done:1313; CHECK: call void @llvm.objc.release(ptr %p)1314; CHECK: {{^}}}1315define void @test25(ptr %p, i1 %x) {1316entry:1317 %f0 = call ptr @llvm.objc.retain(ptr %p)1318 call void @callee()1319 br i1 %x, label %true, label %done1320 1321true:1322 store i8 0, ptr %p1323 br label %done1324 1325done:1326 call void @llvm.objc.release(ptr %p)1327 ret void1328}1329 1330; Don't move a retain/release pair if the retain can be moved1331; but the release can't be moved to balance it.1332 1333; CHECK-LABEL: define void @test26(1334; CHECK: entry:1335; CHECK: call ptr @llvm.objc.retain(ptr %p)1336; CHECK: true:1337; CHECK: done:1338; CHECK: call void @llvm.objc.release(ptr %p)1339; CHECK: {{^}}}1340define void @test26(ptr %p, i1 %x) {1341entry:1342 %f0 = call ptr @llvm.objc.retain(ptr %p)1343 br i1 %x, label %true, label %done1344 1345true:1346 call void @callee()1347 br label %done1348 1349done:1350 store i8 0, ptr %p1351 call void @llvm.objc.release(ptr %p)1352 ret void1353}1354 1355; Don't sink the retain,release into the loop.1356 1357; CHECK-LABEL: define void @test27(1358; CHECK: entry:1359; CHECK: call ptr @llvm.objc.retain(ptr %p)1360; CHECK: loop:1361; CHECK-NOT: @llvm.objc.1362; CHECK: done:1363; CHECK: call void @llvm.objc.release1364; CHECK: {{^}}}1365define void @test27(ptr %p, i1 %x, i1 %y) {1366entry:1367 %f0 = call ptr @llvm.objc.retain(ptr %p)1368 br i1 %x, label %loop, label %done1369 1370loop:1371 call void @callee()1372 store i8 0, ptr %p1373 br i1 %y, label %done, label %loop1374 1375done:1376 call void @llvm.objc.release(ptr %p)1377 ret void1378}1379 1380; Trivial code motion case: Triangle.1381 1382; CHECK-LABEL: define void @test28(1383; CHECK-NOT: @llvm.objc.1384; CHECK: true:1385; CHECK: call ptr @llvm.objc.retain1386; CHECK: call void @callee()1387; CHECK: store1388; CHECK: call void @llvm.objc.release1389; CHECK: done:1390; CHECK-NOT: @llvm.objc.1391; CHECK: {{^}}}1392define void @test28(ptr %p, i1 %x) {1393entry:1394 %f0 = call ptr @llvm.objc.retain(ptr %p)1395 br i1 %x, label %true, label %done1396 1397true:1398 call void @callee()1399 store i8 0, ptr %p1400 br label %done1401 1402done:1403 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !01404 ret void1405}1406 1407; Trivial code motion case: Triangle, but no metadata. Don't move past1408; unrelated memory references!1409 1410; CHECK-LABEL: define void @test28b(1411; CHECK: call ptr @llvm.objc.retain1412; CHECK: true:1413; CHECK-NOT: @llvm.objc.1414; CHECK: call void @callee()1415; CHECK-NOT: @llvm.objc.1416; CHECK: store1417; CHECK-NOT: @llvm.objc.1418; CHECK: done:1419; CHECK: @llvm.objc.release1420; CHECK: {{^}}}1421define void @test28b(ptr %p, i1 %x, ptr noalias %t) {1422entry:1423 %f0 = call ptr @llvm.objc.retain(ptr %p)1424 br i1 %x, label %true, label %done1425 1426true:1427 call void @callee()1428 store i8 0, ptr %p1429 br label %done1430 1431done:1432 store i8 0, ptr %t1433 call void @llvm.objc.release(ptr %p)1434 ret void1435}1436 1437; Trivial code motion case: Triangle, with metadata. Do move past1438; unrelated memory references! And preserve the metadata.1439 1440; CHECK-LABEL: define void @test28c(1441; CHECK-NOT: @llvm.objc.1442; CHECK: true:1443; CHECK: call ptr @llvm.objc.retain1444; CHECK: call void @callee()1445; CHECK: store1446; CHECK: call void @llvm.objc.release(ptr %p) [[NUW]], !clang.imprecise_release1447; CHECK: done:1448; CHECK-NOT: @llvm.objc.1449; CHECK: {{^}}}1450define void @test28c(ptr %p, i1 %x, ptr noalias %t) {1451entry:1452 %f0 = call ptr @llvm.objc.retain(ptr %p)1453 br i1 %x, label %true, label %done1454 1455true:1456 call void @callee()1457 store i8 0, ptr %p1458 br label %done1459 1460done:1461 store i8 0, ptr %t1462 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !01463 ret void1464}1465 1466; Like test28. but with two releases.1467 1468; CHECK-LABEL: define void @test29(1469; CHECK: call ptr @llvm.objc.retain1470; CHECK: true:1471; CHECK: call void @callee()1472; CHECK: store1473; CHECK: done:1474; CHECK: call void @llvm.objc.release1475; CHECK: ohno:1476; CHECK: call void @llvm.objc.release1477; CHECK: {{^}}}1478define void @test29(ptr %p, i1 %x, i1 %y) {1479entry:1480 %f0 = call ptr @llvm.objc.retain(ptr %p)1481 br i1 %x, label %true, label %done1482 1483true:1484 call void @callee()1485 store i8 0, ptr %p1486 br i1 %y, label %done, label %ohno1487 1488done:1489 call void @llvm.objc.release(ptr %p)1490 ret void1491 1492ohno:1493 call void @llvm.objc.release(ptr %p)1494 ret void1495}1496 1497; Basic case with the use and call in a diamond1498; with an extra release.1499 1500; CHECK-LABEL: define void @test30(1501; CHECK: call ptr @llvm.objc.retain1502; CHECK: true:1503; CHECK: call void @callee()1504; CHECK: store1505; CHECK: false:1506; CHECK: done:1507; CHECK: call void @llvm.objc.release1508; CHECK: ohno:1509; CHECK: call void @llvm.objc.release1510; CHECK: {{^}}}1511define void @test30(ptr %p, i1 %x, i1 %y, i1 %z) {1512entry:1513 %f0 = call ptr @llvm.objc.retain(ptr %p)1514 br i1 %x, label %true, label %false1515 1516true:1517 call void @callee()1518 store i8 0, ptr %p1519 br i1 %y, label %done, label %ohno1520 1521false:1522 br i1 %z, label %done, label %ohno1523 1524done:1525 call void @llvm.objc.release(ptr %p)1526 ret void1527 1528ohno:1529 call void @llvm.objc.release(ptr %p)1530 ret void1531}1532 1533; Basic case with a mergeable release.1534 1535; CHECK-LABEL: define void @test31(1536; CHECK: call ptr @llvm.objc.retain(ptr %p)1537; CHECK: call void @callee()1538; CHECK: store1539; CHECK: true:1540; CHECK: call void @llvm.objc.release1541; CHECK: false:1542; CHECK: call void @llvm.objc.release1543; CHECK: ret void1544; CHECK: {{^}}}1545define void @test31(ptr %p, i1 %x) {1546entry:1547 %f0 = call ptr @llvm.objc.retain(ptr %p)1548 call void @callee()1549 store i8 0, ptr %p1550 br i1 %x, label %true, label %false1551true:1552 call void @llvm.objc.release(ptr %p)1553 ret void1554false:1555 call void @llvm.objc.release(ptr %p)1556 ret void1557}1558 1559; Don't consider bitcasts or getelementptrs direct uses.1560 1561; CHECK-LABEL: define void @test32(1562; CHECK: call ptr @llvm.objc.retain1563; CHECK: true:1564; CHECK: call void @callee()1565; CHECK: store1566; CHECK: done:1567; CHECK: call void @llvm.objc.release1568; CHECK: {{^}}}1569define void @test32(ptr %p, i1 %x) {1570entry:1571 %f0 = call ptr @llvm.objc.retain(ptr %p)1572 br i1 %x, label %true, label %done1573 1574true:1575 call void @callee()1576 store i8 0, ptr %p1577 br label %done1578 1579done:1580 call void @llvm.objc.release(ptr %p)1581 ret void1582}1583 1584; Do consider icmps to be direct uses.1585 1586; CHECK-LABEL: define void @test33(1587; CHECK: call ptr @llvm.objc.retain1588; CHECK: true:1589; CHECK: call void @callee()1590; CHECK: icmp1591; CHECK: done:1592; CHECK: call void @llvm.objc.release1593; CHECK: {{^}}}1594define void @test33(ptr %p, i1 %x, ptr %y) {1595entry:1596 %f0 = call ptr @llvm.objc.retain(ptr %p)1597 br i1 %x, label %true, label %done1598 1599true:1600 call void @callee()1601 %v = icmp eq ptr %p, %y1602 br label %done1603 1604done:1605 call void @llvm.objc.release(ptr %p)1606 ret void1607}1608 1609; Delete retain,release if there's just a possible dec and we have imprecise1610; releases.1611 1612; CHECK-LABEL: define void @test34a(1613; CHECK: call ptr @llvm.objc.retain1614; CHECK: true:1615; CHECK: done:1616; CHECK: call void @llvm.objc.release1617; CHECK: {{^}}}1618define void @test34a(ptr %p, i1 %x, ptr %y) {1619entry:1620 %f0 = call ptr @llvm.objc.retain(ptr %p)1621 br i1 %x, label %true, label %done1622 1623true:1624 call void @callee()1625 br label %done1626 1627done:1628 call void @llvm.objc.release(ptr %p)1629 ret void1630}1631 1632; CHECK-LABEL: define void @test34b(1633; CHECK-NOT: @llvm.objc.1634; CHECK: {{^}}}1635define void @test34b(ptr %p, i1 %x, ptr %y) {1636entry:1637 %f0 = call ptr @llvm.objc.retain(ptr %p)1638 br i1 %x, label %true, label %done1639 1640true:1641 call void @callee()1642 br label %done1643 1644done:1645 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !01646 ret void1647}1648 1649 1650; Delete retain,release if there's just a use and we do not have a precise1651; release.1652 1653; Precise.1654; CHECK-LABEL: define void @test35a(1655; CHECK: entry:1656; CHECK: call ptr @llvm.objc.retain1657; CHECK: true:1658; CHECK: done:1659; CHECK: call void @llvm.objc.release1660; CHECK: {{^}}}1661define void @test35a(ptr %p, i1 %x, ptr %y) {1662entry:1663 %f0 = call ptr @llvm.objc.retain(ptr %p)1664 br i1 %x, label %true, label %done1665 1666true:1667 %v = icmp eq ptr %p, %y1668 br label %done1669 1670done:1671 call void @llvm.objc.release(ptr %p)1672 ret void1673}1674 1675; Imprecise.1676; CHECK-LABEL: define void @test35b(1677; CHECK-NOT: @llvm.objc.1678; CHECK: {{^}}}1679define void @test35b(ptr %p, i1 %x, ptr %y) {1680entry:1681 %f0 = call ptr @llvm.objc.retain(ptr %p)1682 br i1 %x, label %true, label %done1683 1684true:1685 %v = icmp eq ptr %p, %y1686 br label %done1687 1688done:1689 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !01690 ret void1691}1692 1693; Delete a retain,release if there's no actual use and we have precise release.1694 1695; CHECK-LABEL: define void @test36a(1696; CHECK: @llvm.objc.retain1697; CHECK: call void @callee()1698; CHECK-NOT: @llvm.objc.1699; CHECK: call void @callee()1700; CHECK: @llvm.objc.release1701; CHECK: {{^}}}1702define void @test36a(ptr %p) {1703entry:1704 call ptr @llvm.objc.retain(ptr %p)1705 call void @callee()1706 call void @callee()1707 call void @llvm.objc.release(ptr %p)1708 ret void1709}1710 1711; Like test36, but with metadata.1712 1713; CHECK-LABEL: define void @test36b(1714; CHECK-NOT: @llvm.objc.1715; CHECK: {{^}}}1716define void @test36b(ptr %p) {1717entry:1718 call ptr @llvm.objc.retain(ptr %p)1719 call void @callee()1720 call void @callee()1721 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !01722 ret void1723}1724 1725; Be aggressive about analyzing phis to eliminate possible uses.1726 1727; CHECK-LABEL: define void @test38(1728; CHECK-NOT: @llvm.objc.1729; CHECK: {{^}}}1730define void @test38(ptr %p, i1 %u, i1 %m, ptr %z, ptr %y, ptr %x, ptr %w) {1731entry:1732 call ptr @llvm.objc.retain(ptr %p)1733 br i1 %u, label %true, label %false1734true:1735 br i1 %m, label %a, label %b1736false:1737 br i1 %m, label %c, label %d1738a:1739 br label %e1740b:1741 br label %e1742c:1743 br label %f1744d:1745 br label %f1746e:1747 %j = phi ptr [ %z, %a ], [ %y, %b ]1748 br label %g1749f:1750 %k = phi ptr [ %w, %c ], [ %x, %d ]1751 br label %g1752g:1753 %h = phi ptr [ %j, %e ], [ %k, %f ]1754 call void @use_pointer(ptr %h)1755 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !01756 ret void1757}1758 1759; Delete retain,release pairs around loops.1760 1761; CHECK-LABEL: define void @test39(1762; CHECK-NOT: @llvm.objc.1763; CHECK: {{^}}}1764define void @test39(ptr %p, i1 %arg) {1765entry:1766 %0 = call ptr @llvm.objc.retain(ptr %p)1767 br label %loop1768 1769loop: ; preds = %loop, %entry1770 br i1 %arg, label %loop, label %exit1771 1772exit: ; preds = %loop1773 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !01774 ret void1775}1776 1777; Delete retain,release pairs around loops containing uses.1778 1779; CHECK-LABEL: define void @test39b(1780; CHECK-NOT: @llvm.objc.1781; CHECK: {{^}}}1782define void @test39b(ptr %p, i1 %arg) {1783entry:1784 %0 = call ptr @llvm.objc.retain(ptr %p)1785 br label %loop1786 1787loop: ; preds = %loop, %entry1788 store i8 0, ptr %01789 br i1 %arg, label %loop, label %exit1790 1791exit: ; preds = %loop1792 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !01793 ret void1794}1795 1796; Delete retain,release pairs around loops containing potential decrements.1797 1798; CHECK-LABEL: define void @test39c(1799; CHECK-NOT: @llvm.objc.1800; CHECK: {{^}}}1801define void @test39c(ptr %p, i1 %arg) {1802entry:1803 %0 = call ptr @llvm.objc.retain(ptr %p)1804 br label %loop1805 1806loop: ; preds = %loop, %entry1807 call void @use_pointer(ptr %0)1808 br i1 %arg, label %loop, label %exit1809 1810exit: ; preds = %loop1811 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !01812 ret void1813}1814 1815; Delete retain,release pairs around loops even if1816; the successors are in a different order.1817 1818; CHECK-LABEL: define void @test40(1819; CHECK-NOT: @llvm.objc.1820; CHECK: {{^}}}1821define void @test40(ptr %p, i1 %arg) {1822entry:1823 %0 = call ptr @llvm.objc.retain(ptr %p)1824 br label %loop1825 1826loop: ; preds = %loop, %entry1827 call void @use_pointer(ptr %0)1828 br i1 %arg, label %exit, label %loop1829 1830exit: ; preds = %loop1831 call void @llvm.objc.release(ptr %0), !clang.imprecise_release !01832 ret void1833}1834 1835; Do the known-incremented retain+release elimination even if the pointer1836; is also autoreleased.1837 1838; CHECK-LABEL: define void @test42(1839; CHECK-NEXT: entry:1840; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)1841; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)1842; CHECK-NEXT: call void @use_pointer(ptr %p)1843; CHECK-NEXT: call void @use_pointer(ptr %p)1844; CHECK-NEXT: call void @use_pointer(ptr %p)1845; CHECK-NEXT: call void @use_pointer(ptr %p)1846; CHECK-NEXT: call void @llvm.objc.release(ptr %p)1847; CHECK-NEXT: ret void1848; CHECK-NEXT: }1849define void @test42(ptr %p) {1850entry:1851 call ptr @llvm.objc.retain(ptr %p)1852 call ptr @llvm.objc.autorelease(ptr %p)1853 call ptr @llvm.objc.retain(ptr %p)1854 call void @use_pointer(ptr %p)1855 call void @use_pointer(ptr %p)1856 call void @llvm.objc.release(ptr %p)1857 call void @use_pointer(ptr %p)1858 call void @use_pointer(ptr %p)1859 call void @llvm.objc.release(ptr %p)1860 ret void1861}1862 1863; Don't the known-incremented retain+release elimination if the pointer is1864; autoreleased and there's an autoreleasePoolPop.1865 1866; CHECK-LABEL: define void @test43(1867; CHECK-NEXT: entry:1868; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)1869; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)1870; CHECK-NEXT: call ptr @llvm.objc.retain1871; CHECK-NEXT: call void @use_pointer(ptr %p)1872; CHECK-NEXT: call void @use_pointer(ptr %p)1873; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop(ptr undef)1874; CHECK-NEXT: call void @llvm.objc.release1875; CHECK-NEXT: ret void1876; CHECK-NEXT: }1877define void @test43(ptr %p) {1878entry:1879 call ptr @llvm.objc.retain(ptr %p)1880 call ptr @llvm.objc.autorelease(ptr %p)1881 call ptr @llvm.objc.retain(ptr %p)1882 call void @use_pointer(ptr %p)1883 call void @use_pointer(ptr %p)1884 call void @llvm.objc.autoreleasePoolPop(ptr undef)1885 call void @llvm.objc.release(ptr %p)1886 ret void1887}1888 1889; Do the known-incremented retain+release elimination if the pointer is1890; autoreleased and there's an autoreleasePoolPush.1891 1892; CHECK-LABEL: define void @test43b(1893; CHECK-NEXT: entry:1894; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)1895; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)1896; CHECK-NEXT: call void @use_pointer(ptr %p)1897; CHECK-NEXT: call void @use_pointer(ptr %p)1898; CHECK-NEXT: call ptr @llvm.objc.autoreleasePoolPush()1899; CHECK-NEXT: call void @use_pointer(ptr %p)1900; CHECK-NEXT: call void @llvm.objc.release1901; CHECK-NEXT: ret void1902; CHECK-NEXT: }1903define void @test43b(ptr %p) {1904entry:1905 call ptr @llvm.objc.retain(ptr %p)1906 call ptr @llvm.objc.autorelease(ptr %p)1907 call ptr @llvm.objc.retain(ptr %p)1908 call void @use_pointer(ptr %p)1909 call void @use_pointer(ptr %p)1910 call ptr @llvm.objc.autoreleasePoolPush()1911 call void @llvm.objc.release(ptr %p)1912 call void @use_pointer(ptr %p)1913 call void @llvm.objc.release(ptr %p)1914 ret void1915}1916 1917; Do retain+release elimination for non-provenance pointers.1918 1919; CHECK-LABEL: define void @test44(1920; CHECK-NOT: llvm.objc.1921; CHECK: {{^}}}1922define void @test44(ptr %pp) {1923 %p = load ptr, ptr %pp1924 %q = call ptr @llvm.objc.retain(ptr %p)1925 call void @llvm.objc.release(ptr %q)1926 ret void1927}1928 1929; Don't delete retain+release with an unknown-provenance1930; may-alias llvm.objc.release between them.1931 1932; CHECK-LABEL: define void @test45(1933; CHECK: call ptr @llvm.objc.retain(ptr %p)1934; CHECK: call void @llvm.objc.release(ptr %q)1935; CHECK: call void @use_pointer(ptr %p)1936; CHECK: call void @llvm.objc.release(ptr %p)1937; CHECK: {{^}}}1938define void @test45(ptr %pp, ptr %qq) {1939 %p = load ptr, ptr %pp1940 %q = load ptr, ptr %qq1941 call ptr @llvm.objc.retain(ptr %p)1942 call void @llvm.objc.release(ptr %q)1943 call void @use_pointer(ptr %p)1944 call void @llvm.objc.release(ptr %p)1945 ret void1946}1947 1948; Don't delete retain and autorelease here.1949 1950; CHECK-LABEL: define void @test46(1951; CHECK: tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]1952; CHECK: true:1953; CHECK: call ptr @llvm.objc.autorelease(ptr %p) [[NUW]]1954; CHECK: {{^}}}1955define void @test46(ptr %p, i1 %a) {1956entry:1957 call ptr @llvm.objc.retain(ptr %p)1958 br i1 %a, label %true, label %false1959 1960true:1961 call ptr @llvm.objc.autorelease(ptr %p)1962 call void @use_pointer(ptr %p)1963 ret void1964 1965false:1966 ret void1967}1968 1969; Delete no-op cast calls.1970 1971; CHECK-LABEL: define ptr @test47(1972; CHECK-NOT: call1973; CHECK: ret ptr %p1974; CHECK: {{^}}}1975define ptr @test47(ptr %p) nounwind {1976 %x = call ptr @llvm.objc.retainedObject(ptr %p)1977 ret ptr %x1978}1979 1980; Delete no-op cast calls.1981 1982; CHECK-LABEL: define ptr @test48(1983; CHECK-NOT: call1984; CHECK: ret ptr %p1985; CHECK: {{^}}}1986define ptr @test48(ptr %p) nounwind {1987 %x = call ptr @llvm.objc.unretainedObject(ptr %p)1988 ret ptr %x1989}1990 1991; Delete no-op cast calls.1992 1993; CHECK-LABEL: define ptr @test49(1994; CHECK-NOT: call1995; CHECK: ret ptr %p1996; CHECK: {{^}}}1997define ptr @test49(ptr %p) nounwind {1998 %x = call ptr @llvm.objc.unretainedPointer(ptr %p)1999 ret ptr %x2000}2001 2002; Do delete retain+release with intervening stores of the address value if we2003; have imprecise release attached to llvm.objc.release.2004 2005; CHECK-LABEL: define void @test50a(2006; CHECK-NEXT: call ptr @llvm.objc.retain2007; CHECK-NEXT: call void @callee2008; CHECK-NEXT: store2009; CHECK-NEXT: call void @llvm.objc.release2010; CHECK-NEXT: ret void2011; CHECK-NEXT: }2012define void @test50a(ptr %p, ptr %pp) {2013 call ptr @llvm.objc.retain(ptr %p)2014 call void @callee()2015 store ptr %p, ptr %pp2016 call void @llvm.objc.release(ptr %p)2017 ret void2018}2019 2020; CHECK-LABEL: define void @test50b(2021; CHECK-NOT: @llvm.objc.2022; CHECK: {{^}}}2023define void @test50b(ptr %p, ptr %pp) {2024 call ptr @llvm.objc.retain(ptr %p)2025 call void @callee()2026 store ptr %p, ptr %pp2027 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !02028 ret void2029}2030 2031 2032; Don't delete retain+release with intervening stores through the2033; address value.2034 2035; CHECK-LABEL: define void @test51a(2036; CHECK: call ptr @llvm.objc.retain(ptr %p)2037; CHECK: call void @llvm.objc.release(ptr %p)2038; CHECK: ret void2039; CHECK: {{^}}}2040define void @test51a(ptr %p) {2041 call ptr @llvm.objc.retain(ptr %p)2042 call void @callee()2043 store i8 0, ptr %p2044 call void @llvm.objc.release(ptr %p)2045 ret void2046}2047 2048; CHECK-LABEL: define void @test51b(2049; CHECK: call ptr @llvm.objc.retain(ptr %p)2050; CHECK: call void @llvm.objc.release(ptr %p)2051; CHECK: ret void2052; CHECK: {{^}}}2053define void @test51b(ptr %p) {2054 call ptr @llvm.objc.retain(ptr %p)2055 call void @callee()2056 store i8 0, ptr %p2057 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !02058 ret void2059}2060 2061; Don't delete retain+release with intervening use of a pointer of2062; unknown provenance.2063 2064; CHECK-LABEL: define void @test52a(2065; CHECK: call ptr @llvm.objc.retain2066; CHECK: call void @callee()2067; CHECK: call void @use_pointer(ptr %z)2068; CHECK: call void @llvm.objc.release2069; CHECK: ret void2070; CHECK: {{^}}}2071define void @test52a(ptr %zz, ptr %pp) {2072 %p = load ptr, ptr %pp2073 %1 = call ptr @llvm.objc.retain(ptr %p)2074 call void @callee()2075 %z = load ptr, ptr %zz2076 call void @use_pointer(ptr %z)2077 call void @llvm.objc.release(ptr %p)2078 ret void2079}2080 2081; CHECK-LABEL: define void @test52b(2082; CHECK: call ptr @llvm.objc.retain2083; CHECK: call void @callee()2084; CHECK: call void @use_pointer(ptr %z)2085; CHECK: call void @llvm.objc.release2086; CHECK: ret void2087; CHECK: {{^}}}2088define void @test52b(ptr %zz, ptr %pp) {2089 %p = load ptr, ptr %pp2090 %1 = call ptr @llvm.objc.retain(ptr %p)2091 call void @callee()2092 %z = load ptr, ptr %zz2093 call void @use_pointer(ptr %z)2094 call void @llvm.objc.release(ptr %p), !clang.imprecise_release !02095 ret void2096}2097 2098; Like test52, but the pointer has function type, so it's assumed to2099; be not reference counted.2100; Oops. That's wrong. Clang sometimes uses function types gratuitously.2101; See rdar://10551239.2102 2103; CHECK-LABEL: define void @test53(2104; CHECK: @llvm.objc.2105; CHECK: {{^}}}2106define void @test53(ptr %zz, ptr %pp) {2107 %p = load ptr, ptr %pp2108 %1 = call ptr @llvm.objc.retain(ptr %p)2109 call void @callee()2110 %z = load ptr, ptr %zz2111 call void @callee_fnptr(ptr %z)2112 call void @llvm.objc.release(ptr %p)2113 ret void2114}2115 2116; Convert autorelease to release if the value is unused.2117 2118; CHECK-LABEL: define void @test54(2119; CHECK: call ptr @returner()2120; CHECK-NEXT: call void @llvm.objc.release(ptr %t) [[NUW]], !clang.imprecise_release ![[RELEASE]]2121; CHECK-NEXT: ret void2122; CHECK: {{^}}}2123define void @test54() {2124 %t = call ptr @returner()2125 call ptr @llvm.objc.autorelease(ptr %t)2126 ret void2127}2128 2129; Nested retain+release pairs. Delete them both.2130 2131; CHECK-LABEL: define void @test55(2132; CHECK-NOT: @objc2133; CHECK: {{^}}}2134define void @test55(ptr %x) {2135entry:2136 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind2137 %1 = call ptr @llvm.objc.retain(ptr %x) nounwind2138 call void @llvm.objc.release(ptr %x) nounwind2139 call void @llvm.objc.release(ptr %x) nounwind2140 ret void2141}2142 2143; Nested retain+release pairs where the inner pair depends2144; on the outer pair to be removed, and then the outer pair2145; can be partially eliminated. Plus an extra outer pair to2146; eliminate, for fun.2147 2148; CHECK-LABEL: define void @test56(2149; CHECK-NOT: @objc2150; CHECK: if.then:2151; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]2152; CHECK-NEXT: tail call void @use_pointer(ptr %x)2153; CHECK-NEXT: tail call void @use_pointer(ptr %x)2154; CHECK-NEXT: tail call void @llvm.objc.release(ptr %x) [[NUW]], !clang.imprecise_release ![[RELEASE]]2155; CHECK-NEXT: br label %if.end2156; CHECK-NOT: @objc2157; CHECK: {{^}}}2158define void @test56(ptr %x, i32 %n) {2159entry:2160 %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind2161 %1 = tail call ptr @llvm.objc.retain(ptr %0) nounwind2162 %tobool = icmp eq i32 %n, 02163 br i1 %tobool, label %if.end, label %if.then2164 2165if.then: ; preds = %entry2166 %2 = tail call ptr @llvm.objc.retain(ptr %1) nounwind2167 tail call void @use_pointer(ptr %2)2168 tail call void @use_pointer(ptr %2)2169 tail call void @llvm.objc.release(ptr %2) nounwind, !clang.imprecise_release !02170 br label %if.end2171 2172if.end: ; preds = %entry, %if.then2173 tail call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !02174 tail call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !02175 ret void2176}2177 2178; When there are adjacent retain+release pairs, the first one is known2179; unnecessary because the presence of the second one means that the first one2180; won't be deleting the object.2181 2182; CHECK-LABEL: define void @test57(2183; CHECK-NEXT: entry:2184; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]2185; CHECK-NEXT: call void @use_pointer(ptr %x)2186; CHECK-NEXT: call void @use_pointer(ptr %x)2187; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]2188; CHECK-NEXT: call void @use_pointer(ptr %x)2189; CHECK-NEXT: call void @use_pointer(ptr %x)2190; CHECK-NEXT: call void @llvm.objc.release(ptr %x) [[NUW]]2191; CHECK-NEXT: ret void2192; CHECK-NEXT: }2193define void @test57(ptr %x) nounwind {2194entry:2195 call ptr @llvm.objc.retain(ptr %x) nounwind2196 call ptr @llvm.objc.retain(ptr %x) nounwind2197 call void @use_pointer(ptr %x)2198 call void @use_pointer(ptr %x)2199 call void @llvm.objc.release(ptr %x) nounwind2200 call ptr @llvm.objc.retain(ptr %x) nounwind2201 call void @use_pointer(ptr %x)2202 call void @use_pointer(ptr %x)2203 call void @llvm.objc.release(ptr %x) nounwind2204 ret void2205}2206 2207; An adjacent retain+release pair is sufficient even if it will be2208; removed itself.2209 2210; CHECK-LABEL: define void @test58(2211; CHECK-NEXT: entry:2212; CHECK-NEXT: @llvm.objc.retain2213; CHECK-NEXT: call void @use_pointer(ptr %x)2214; CHECK-NEXT: call void @use_pointer(ptr %x)2215; CHECK-NEXT: ret void2216; CHECK-NEXT: }2217define void @test58(ptr %x) nounwind {2218entry:2219 call ptr @llvm.objc.retain(ptr %x) nounwind2220 call ptr @llvm.objc.retain(ptr %x) nounwind2221 call void @use_pointer(ptr %x)2222 call void @use_pointer(ptr %x)2223 call void @llvm.objc.release(ptr %x) nounwind2224 call ptr @llvm.objc.retain(ptr %x) nounwind2225 call void @llvm.objc.release(ptr %x) nounwind2226 ret void2227}2228 2229; Don't delete the second retain+release pair in an adjacent set.2230 2231; CHECK-LABEL: define void @test59(2232; CHECK-NEXT: entry:2233; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]2234; CHECK-NEXT: call void @use_pointer(ptr %x)2235; CHECK-NEXT: call void @use_pointer(ptr %x)2236; CHECK-NEXT: call void @llvm.objc.release(ptr %x) [[NUW]]2237; CHECK-NEXT: ret void2238; CHECK-NEXT: }2239define void @test59(ptr %x) nounwind {2240entry:2241 %a = call ptr @llvm.objc.retain(ptr %x) nounwind2242 call void @llvm.objc.release(ptr %x) nounwind2243 %b = call ptr @llvm.objc.retain(ptr %x) nounwind2244 call void @use_pointer(ptr %x)2245 call void @use_pointer(ptr %x)2246 call void @llvm.objc.release(ptr %x) nounwind2247 ret void2248}2249 2250; Constant pointers to objects don't need reference counting.2251 2252@constptr = external constant ptr2253@something = external global ptr2254 2255; We have a precise lifetime retain/release here. We can not remove them since2256; @something is not constant.2257 2258; CHECK-LABEL: define void @test60a(2259; CHECK: call ptr @llvm.objc.retain2260; CHECK: call void @llvm.objc.release2261; CHECK: {{^}}}2262define void @test60a() {2263 %t = load ptr, ptr @constptr2264 %s = load ptr, ptr @something2265 call ptr @llvm.objc.retain(ptr %s)2266 call void @callee()2267 call void @use_pointer(ptr %t)2268 call void @llvm.objc.release(ptr %s)2269 ret void2270}2271 2272; CHECK-LABEL: define void @test60b(2273; CHECK: call ptr @llvm.objc.retain2274; CHECK-NOT: call ptr @llvm.objc.retain2275; CHECK-NOT: call ptr @llvm.objc.release2276; CHECK: {{^}}}2277define void @test60b() {2278 %t = load ptr, ptr @constptr2279 %s = load ptr, ptr @something2280 call ptr @llvm.objc.retain(ptr %t)2281 call ptr @llvm.objc.retain(ptr %t)2282 call void @callee()2283 call void @use_pointer(ptr %s)2284 call void @llvm.objc.release(ptr %t)2285 ret void2286}2287 2288; CHECK-LABEL: define void @test60c(2289; CHECK-NOT: @llvm.objc.2290; CHECK: {{^}}}2291define void @test60c() {2292 %t = load ptr, ptr @constptr2293 %s = load ptr, ptr @something2294 call ptr @llvm.objc.retain(ptr %t)2295 call void @callee()2296 call void @use_pointer(ptr %s)2297 call void @llvm.objc.release(ptr %t), !clang.imprecise_release !02298 ret void2299}2300 2301; CHECK-LABEL: define void @test60d(2302; CHECK-NOT: @llvm.objc.2303; CHECK: {{^}}}2304define void @test60d() {2305 %t = load ptr, ptr @constptr2306 %s = load ptr, ptr @something2307 call ptr @llvm.objc.retain(ptr %t)2308 call void @callee()2309 call void @use_pointer(ptr %s)2310 call void @llvm.objc.release(ptr %t)2311 ret void2312}2313 2314; CHECK-LABEL: define void @test60e(2315; CHECK-NOT: @llvm.objc.2316; CHECK: {{^}}}2317define void @test60e() {2318 %t = load ptr, ptr @constptr2319 %s = load ptr, ptr @something2320 call ptr @llvm.objc.retain(ptr %t)2321 call void @callee()2322 call void @use_pointer(ptr %s)2323 call void @llvm.objc.release(ptr %t), !clang.imprecise_release !02324 ret void2325}2326 2327; Constant pointers to objects don't need to be considered related to other2328; pointers.2329 2330; CHECK-LABEL: define void @test61(2331; CHECK-NOT: @llvm.objc.2332; CHECK: {{^}}}2333define void @test61() {2334 %t = load ptr, ptr @constptr2335 call ptr @llvm.objc.retain(ptr %t)2336 call void @callee()2337 call void @use_pointer(ptr %t)2338 call void @llvm.objc.release(ptr %t)2339 ret void2340}2341 2342; Delete a retain matched by releases when one is inside the loop and the2343; other is outside the loop.2344 2345; CHECK-LABEL: define void @test62(2346; CHECK-NOT: @llvm.objc.2347; CHECK: {{^}}}2348define void @test62(ptr %x, ptr %p) nounwind {2349entry:2350 br label %loop2351 2352loop:2353 call ptr @llvm.objc.retain(ptr %x)2354 %q = load i1, ptr %p2355 br i1 %q, label %loop.more, label %exit2356 2357loop.more:2358 call void @llvm.objc.release(ptr %x)2359 br label %loop2360 2361exit:2362 call void @llvm.objc.release(ptr %x)2363 ret void2364}2365 2366; Like test62 but with no release in exit.2367; Don't delete anything!2368 2369; CHECK-LABEL: define void @test63(2370; CHECK: loop:2371; CHECK: tail call ptr @llvm.objc.retain(ptr %x)2372; CHECK: loop.more:2373; CHECK: call void @llvm.objc.release(ptr %x)2374; CHECK: {{^}}}2375define void @test63(ptr %x, ptr %p) nounwind {2376entry:2377 br label %loop2378 2379loop:2380 call ptr @llvm.objc.retain(ptr %x)2381 %q = load i1, ptr %p2382 br i1 %q, label %loop.more, label %exit2383 2384loop.more:2385 call void @llvm.objc.release(ptr %x)2386 br label %loop2387 2388exit:2389 ret void2390}2391 2392; Like test62 but with no release in loop.more.2393; Don't delete anything!2394 2395; CHECK-LABEL: define void @test64(2396; CHECK: loop:2397; CHECK: tail call ptr @llvm.objc.retain(ptr %x)2398; CHECK: exit:2399; CHECK: call void @llvm.objc.release(ptr %x)2400; CHECK: {{^}}}2401define void @test64(ptr %x, ptr %p) nounwind {2402entry:2403 br label %loop2404 2405loop:2406 call ptr @llvm.objc.retain(ptr %x)2407 %q = load i1, ptr %p2408 br i1 %q, label %loop.more, label %exit2409 2410loop.more:2411 br label %loop2412 2413exit:2414 call void @llvm.objc.release(ptr %x)2415 ret void2416}2417 2418; Move an autorelease past a phi with a null.2419 2420; CHECK-LABEL: define ptr @test65(2421; CHECK: if.then:2422; CHECK: call ptr @llvm.objc.autorelease(2423; CHECK: return:2424; CHECK-NOT: @llvm.objc.autorelease2425; CHECK: {{^}}}2426define ptr @test65(i1 %x) {2427entry:2428 br i1 %x, label %return, label %if.then2429 2430if.then: ; preds = %entry2431 %c = call ptr @returner()2432 %s = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind2433 br label %return2434 2435return: ; preds = %if.then, %entry2436 %retval = phi ptr [ %s, %if.then ], [ null, %entry ]2437 %q = call ptr @llvm.objc.autorelease(ptr %retval) nounwind2438 ret ptr %retval2439}2440 2441; Don't move an autorelease past an autorelease pool boundary.2442 2443; CHECK-LABEL: define ptr @test65b(2444; CHECK: if.then:2445; CHECK-NOT: @llvm.objc.autorelease2446; CHECK: return:2447; CHECK: call ptr @llvm.objc.autorelease(2448; CHECK: {{^}}}2449define ptr @test65b(i1 %x) {2450entry:2451 %t = call ptr @llvm.objc.autoreleasePoolPush()2452 br i1 %x, label %return, label %if.then2453 2454if.then: ; preds = %entry2455 %c = call ptr @returner()2456 %s = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind2457 br label %return2458 2459return: ; preds = %if.then, %entry2460 %retval = phi ptr [ %s, %if.then ], [ null, %entry ]2461 call void @llvm.objc.autoreleasePoolPop(ptr %t)2462 %q = call ptr @llvm.objc.autorelease(ptr %retval) nounwind2463 ret ptr %retval2464}2465 2466; Don't move an autoreleaseReuturnValue, which would break2467; the RV optimization.2468 2469; CHECK-LABEL: define ptr @test65c(2470; CHECK: if.then:2471; CHECK-NOT: @llvm.objc.autorelease2472; CHECK: return:2473; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(2474; CHECK: {{^}}}2475define ptr @test65c(i1 %x) {2476entry:2477 br i1 %x, label %return, label %if.then2478 2479if.then: ; preds = %entry2480 %c = call ptr @returner()2481 %s = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind2482 br label %return2483 2484return: ; preds = %if.then, %entry2485 %retval = phi ptr [ %s, %if.then ], [ null, %entry ]2486 %q = call ptr @llvm.objc.autoreleaseReturnValue(ptr %retval) nounwind2487 ret ptr %retval2488}2489 2490; CHECK-LABEL: define ptr @test65d(2491; CHECK: if.then:2492; CHECK-NOT: @llvm.objc.autorelease2493; CHECK: return:2494; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(2495; CHECK: {{^}}}2496define ptr @test65d(i1 %x) {2497entry:2498 br i1 %x, label %return, label %if.then2499 2500if.then: ; preds = %entry2501 %c = call ptr @returner()2502 %s = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %c) nounwind2503 br label %return2504 2505return: ; preds = %if.then, %entry2506 %retval = phi ptr [ %s, %if.then ], [ null, %entry ]2507 %q = call ptr @llvm.objc.autoreleaseReturnValue(ptr %retval) nounwind2508 ret ptr %retval2509}2510 2511; An llvm.objc.retain can serve as a may-use for a different pointer.2512; rdar://119318232513 2514; CHECK-LABEL: define void @test66a(2515; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]2516; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]2517; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]2518; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]2519; CHECK: {{^}}}2520define void @test66a(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {2521entry:2522 br i1 %tobool, label %cond.true, label %cond.end2523 2524cond.true:2525 br label %cond.end2526 2527cond.end: ; preds = %cond.true, %entry2528 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ]2529 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind2530 tail call void @llvm.objc.release(ptr %call) nounwind2531 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar2532 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind2533 tail call void @llvm.objc.release(ptr %cond) nounwind2534 ret void2535}2536 2537; CHECK-LABEL: define void @test66b(2538; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]2539; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]2540; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]2541; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]2542; CHECK: {{^}}}2543define void @test66b(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {2544entry:2545 br i1 %tobool, label %cond.true, label %cond.end2546 2547cond.true:2548 br label %cond.end2549 2550cond.end: ; preds = %cond.true, %entry2551 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ]2552 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind2553 tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !02554 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar2555 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind2556 tail call void @llvm.objc.release(ptr %cond) nounwind2557 ret void2558}2559 2560; CHECK-LABEL: define void @test66c(2561; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]2562; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]2563; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]2564; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]2565; CHECK: {{^}}}2566define void @test66c(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {2567entry:2568 br i1 %tobool, label %cond.true, label %cond.end2569 2570cond.true:2571 br label %cond.end2572 2573cond.end: ; preds = %cond.true, %entry2574 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ]2575 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind2576 tail call void @llvm.objc.release(ptr %call) nounwind2577 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar2578 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind, !clang.imprecise_release !02579 tail call void @llvm.objc.release(ptr %cond) nounwind2580 ret void2581}2582 2583; CHECK-LABEL: define void @test66d(2584; CHECK: tail call ptr @llvm.objc.retain(ptr %cond) [[NUW]]2585; CHECK: tail call void @llvm.objc.release(ptr %call) [[NUW]]2586; CHECK: tail call ptr @llvm.objc.retain(ptr %tmp8) [[NUW]]2587; CHECK: tail call void @llvm.objc.release(ptr %cond) [[NUW]]2588; CHECK: {{^}}}2589define void @test66d(ptr %tmp5, ptr %bar, i1 %tobool, i1 %tobool1, ptr %call) {2590entry:2591 br i1 %tobool, label %cond.true, label %cond.end2592 2593cond.true:2594 br label %cond.end2595 2596cond.end: ; preds = %cond.true, %entry2597 %cond = phi ptr [ %tmp5, %cond.true ], [ %call, %entry ]2598 %tmp7 = tail call ptr @llvm.objc.retain(ptr %cond) nounwind2599 tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !02600 %tmp8 = select i1 %tobool1, ptr %cond, ptr %bar2601 %tmp9 = tail call ptr @llvm.objc.retain(ptr %tmp8) nounwind2602 tail call void @llvm.objc.release(ptr %cond) nounwind, !clang.imprecise_release !02603 ret void2604}2605 2606; A few real-world testcases.2607 2608@.str4 = private unnamed_addr constant [33 x i8] c"-[A z] = { %f, %f, { %f, %f } }\0A\00"2609@"OBJC_IVAR_$_A.myZ" = global i64 20, section "__DATA, __objc_const", align 82610declare i32 @printf(ptr captures(none), ...) nounwind2611declare i32 @puts(ptr captures(none)) nounwind2612@str = internal constant [16 x i8] c"-[ Top0 _getX ]\00"2613 2614; FIXME: Should be able to eliminate the retain and release2615; CHECK-LABEL: define { <2 x float>, <2 x float> } @"\01-[A z]"(ptr %self, ptr captures(none) %_cmd)2616; CHECK: tail call ptr @llvm.objc.retain(ptr %self)2617; CHECK-NEXT: %call = tail call i32 (ptr, ...) @printf(2618; CHECK: tail call void @llvm.objc.release(ptr %self)2619; CHECK: {{^}}}2620define { <2 x float>, <2 x float> } @"\01-[A z]"(ptr %self, ptr captures(none) %_cmd) nounwind {2621invoke.cont:2622 %i1 = tail call ptr @llvm.objc.retain(ptr %self) nounwind2623 tail call void @llvm.dbg.value(metadata ptr %self, metadata !DILocalVariable(scope: !2), metadata !DIExpression()), !dbg !DILocation(scope: !2)2624 tail call void @llvm.dbg.value(metadata ptr %self, metadata !DILocalVariable(scope: !2), metadata !DIExpression()), !dbg !DILocation(scope: !2)2625 %ivar = load i64, ptr @"OBJC_IVAR_$_A.myZ", align 82626 %add.ptr = getelementptr i8, ptr %self, i64 %ivar2627 %tmp2 = load float, ptr %add.ptr, align 42628 %conv = fpext float %tmp2 to double2629 %add.ptr.sum = add i64 %ivar, 42630 %tmp6 = getelementptr inbounds i8, ptr %self, i64 %add.ptr.sum2631 %tmp7 = load float, ptr %tmp6, align 42632 %conv8 = fpext float %tmp7 to double2633 %add.ptr.sum36 = add i64 %ivar, 82634 %tmp12 = getelementptr inbounds i8, ptr %self, i64 %add.ptr.sum362635 %tmp13 = load float, ptr %tmp12, align 42636 %conv14 = fpext float %tmp13 to double2637 %tmp12.sum = add i64 %ivar, 122638 %arrayidx19 = getelementptr inbounds i8, ptr %self, i64 %tmp12.sum2639 %tmp20 = load float, ptr %arrayidx19, align 42640 %conv21 = fpext float %tmp20 to double2641 %call = tail call i32 (ptr, ...) @printf(ptr @.str4, double %conv, double %conv8, double %conv14, double %conv21)2642 %ivar23 = load i64, ptr @"OBJC_IVAR_$_A.myZ", align 82643 %add.ptr24 = getelementptr i8, ptr %self, i64 %ivar232644 %srcval = load i128, ptr %add.ptr24, align 42645 tail call void @llvm.objc.release(ptr %self) nounwind2646 %tmp29 = trunc i128 %srcval to i642647 %tmp30 = bitcast i64 %tmp29 to <2 x float>2648 %tmp31 = insertvalue { <2 x float>, <2 x float> } undef, <2 x float> %tmp30, 02649 %tmp32 = lshr i128 %srcval, 642650 %tmp33 = trunc i128 %tmp32 to i642651 %tmp34 = bitcast i64 %tmp33 to <2 x float>2652 %tmp35 = insertvalue { <2 x float>, <2 x float> } %tmp31, <2 x float> %tmp34, 12653 ret { <2 x float>, <2 x float> } %tmp352654}2655 2656; FIXME: Should be able to eliminate the retain and release2657; CHECK-LABEL: @"\01-[Top0 _getX]"(ptr %self, ptr captures(none) %_cmd)2658; CHECK: tail call ptr @llvm.objc.retain(ptr %self)2659; CHECK: %puts = tail call i32 @puts2660; CHECK: tail call void @llvm.objc.release(ptr %self)2661define i32 @"\01-[Top0 _getX]"(ptr %self, ptr captures(none) %_cmd) nounwind {2662invoke.cont:2663 %i1 = tail call ptr @llvm.objc.retain(ptr %self) nounwind2664 %puts = tail call i32 @puts(ptr @str)2665 tail call void @llvm.objc.release(ptr %self) nounwind2666 ret i32 02667}2668 2669@"\01L_OBJC_METH_VAR_NAME_" = internal global [5 x i8] c"frob\00", section "__TEXT,__cstring,cstring_literals", align 1@"\01L_OBJC_SELECTOR_REFERENCES_" = internal global ptr @"\01L_OBJC_METH_VAR_NAME_", section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2670@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip"2671@llvm.used = appending global [3 x ptr] [ptr @"\01L_OBJC_METH_VAR_NAME_", ptr @"\01L_OBJC_SELECTOR_REFERENCES_", ptr @"\01L_OBJC_IMAGE_INFO"], section "llvm.metadata"2672 2673; A simple loop. Eliminate the retain and release inside of it!2674 2675; CHECK: define void @loop(ptr %x, i64 %n) {2676; CHECK: for.body:2677; CHECK-NOT: @llvm.objc.2678; CHECK: @objc_msgSend2679; CHECK-NOT: @llvm.objc.2680; CHECK: for.end:2681; CHECK: {{^}}}2682define void @loop(ptr %x, i64 %n) {2683entry:2684 %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind2685 %cmp9 = icmp sgt i64 %n, 02686 br i1 %cmp9, label %for.body, label %for.end2687 2688for.body: ; preds = %entry, %for.body2689 %i.010 = phi i64 [ %inc, %for.body ], [ 0, %entry ]2690 %1 = tail call ptr @llvm.objc.retain(ptr %x) nounwind2691 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_", align 82692 %call = tail call ptr (ptr, ptr, ...) @objc_msgSend(ptr %1, ptr %tmp5)2693 tail call void @llvm.objc.release(ptr %1) nounwind, !clang.imprecise_release !02694 %inc = add nsw i64 %i.010, 12695 %exitcond = icmp eq i64 %inc, %n2696 br i1 %exitcond, label %for.end, label %for.body2697 2698for.end: ; preds = %for.body, %entry2699 tail call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !02700 ret void2701}2702 2703; ObjCARCOpt can delete the retain,release on self.2704 2705; CHECK: define void @TextEditTest(ptr %self, ptr %pboard) {2706; CHECK-NOT: call ptr @llvm.objc.retain(ptr %tmp7)2707; CHECK: {{^}}}2708 2709%0 = type { ptr, ptr }2710%1 = type opaque2711%2 = type opaque2712%3 = type opaque2713%4 = type opaque2714%5 = type opaque2715%struct.NSConstantString = type { ptr, i32, ptr, i64 }2716%struct._NSRange = type { i64, i64 }2717%struct.__CFString = type opaque2718%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }2719%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }2720%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }2721%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }2722%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }2723%struct._message_ref_t = type { ptr, ptr }2724%struct._objc_cache = type opaque2725%struct._objc_method = type { ptr, ptr, ptr }2726%struct._objc_protocol_list = type { i64, [0 x ptr] }2727%struct._prop_list_t = type { i32, i32, [0 x %struct._message_ref_t] }2728%struct._protocol_t = type { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, i32, i32 }2729 2730@"\01L_OBJC_CLASSLIST_REFERENCES_$_17" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82731@kUTTypePlainText = external constant ptr2732@"\01L_OBJC_SELECTOR_REFERENCES_19" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2733@"\01L_OBJC_SELECTOR_REFERENCES_21" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2734@"\01L_OBJC_SELECTOR_REFERENCES_23" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2735@"\01L_OBJC_SELECTOR_REFERENCES_25" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2736@"\01L_OBJC_CLASSLIST_REFERENCES_$_26" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82737@"\01L_OBJC_SELECTOR_REFERENCES_28" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2738@"\01L_OBJC_CLASSLIST_REFERENCES_$_29" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82739@"\01L_OBJC_SELECTOR_REFERENCES_31" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2740@"\01L_OBJC_SELECTOR_REFERENCES_33" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2741@"\01L_OBJC_SELECTOR_REFERENCES_35" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2742@"\01L_OBJC_SELECTOR_REFERENCES_37" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2743@"\01L_OBJC_CLASSLIST_REFERENCES_$_38" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82744@"\01L_OBJC_SELECTOR_REFERENCES_40" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2745@"\01L_OBJC_SELECTOR_REFERENCES_42" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2746@_unnamed_cfstring_44 = external hidden constant %struct.NSConstantString, section "__DATA,__cfstring"2747@"\01L_OBJC_SELECTOR_REFERENCES_46" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2748@"\01L_OBJC_SELECTOR_REFERENCES_48" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2749@"\01l_objc_msgSend_fixup_isEqual_" = external hidden global %0, section "__DATA, __objc_msgrefs, coalesced", align 162750@"\01L_OBJC_CLASSLIST_REFERENCES_$_50" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82751@NSCocoaErrorDomain = external constant ptr2752@"\01L_OBJC_CLASSLIST_REFERENCES_$_51" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82753@NSFilePathErrorKey = external constant ptr2754@"\01L_OBJC_SELECTOR_REFERENCES_53" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2755@"\01L_OBJC_SELECTOR_REFERENCES_55" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2756@"\01L_OBJC_CLASSLIST_REFERENCES_$_56" = external hidden global ptr, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 82757@"\01L_OBJC_SELECTOR_REFERENCES_58" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2758@"\01L_OBJC_SELECTOR_REFERENCES_60" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"2759 2760declare ptr @truncatedString(ptr, i64)2761define void @TextEditTest(ptr %self, ptr %pboard) {2762entry:2763 %err = alloca ptr, align 82764 %tmp8 = call ptr @llvm.objc.retain(ptr %self) nounwind2765 store ptr null, ptr %err, align 82766 %tmp1 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_17", align 82767 %tmp2 = load ptr, ptr @kUTTypePlainText, align 82768 %tmp3 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_19", align 82769 %call5 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp1, ptr %tmp3, ptr %tmp2)2770 %tmp5 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_21", align 82771 %call76 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %pboard, ptr %tmp5, ptr %call5)2772 %tmp9 = call ptr @llvm.objc.retain(ptr %call76) nounwind2773 %tobool = icmp eq ptr %tmp9, null2774 br i1 %tobool, label %end, label %land.lhs.true2775 2776land.lhs.true: ; preds = %entry2777 %tmp11 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_23", align 82778 %call137 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %pboard, ptr %tmp11, ptr %tmp9)2779 %tmp10 = call ptr @llvm.objc.retain(ptr %call137) nounwind2780 call void @llvm.objc.release(ptr null) nounwind2781 %tmp12 = call ptr @llvm.objc.retain(ptr %call137) nounwind2782 call void @llvm.objc.release(ptr null) nounwind2783 %tobool16 = icmp eq ptr %call137, null2784 br i1 %tobool16, label %end, label %if.then2785 2786if.then: ; preds = %land.lhs.true2787 %tmp19 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_25", align 82788 %call21 = call signext i8 @objc_msgSend(ptr %call137, ptr %tmp19)2789 %tobool22 = icmp eq i8 %call21, 02790 br i1 %tobool22, label %if.then44, label %land.lhs.true232791 2792land.lhs.true23: ; preds = %if.then2793 %tmp24 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_26", align 82794 %tmp26 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_28", align 82795 %call2822 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp24, ptr %tmp26, ptr %call137)2796 %tmp14 = call ptr @llvm.objc.retain(ptr %call2822) nounwind2797 call void @llvm.objc.release(ptr null) nounwind2798 %tobool30 = icmp eq ptr %call2822, null2799 br i1 %tobool30, label %if.then44, label %if.end2800 2801if.end: ; preds = %land.lhs.true232802 %tmp32 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_29", align 82803 %tmp33 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_31", align 82804 %call35 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp32, ptr %tmp33)2805 %tmp37 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_33", align 82806 %call3923 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call35, ptr %tmp37, ptr %call2822, i32 signext 1, ptr %err)2807 %cmp = icmp eq ptr %call3923, null2808 br i1 %cmp, label %if.then44, label %end2809 2810if.then44: ; preds = %if.end, %land.lhs.true23, %if.then2811 %url.025 = phi ptr [ %call2822, %if.end ], [ %call2822, %land.lhs.true23 ], [ null, %if.then ]2812 %tmp49 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_35", align 82813 %call51 = call %struct._NSRange @objc_msgSend(ptr %call137, ptr %tmp49, i64 0, i64 0)2814 %call513 = extractvalue %struct._NSRange %call51, 02815 %call514 = extractvalue %struct._NSRange %call51, 12816 %tmp52 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_37", align 82817 %call548 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call137, ptr %tmp52, i64 %call513, i64 %call514)2818 %tmp55 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_38", align 82819 %tmp56 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_40", align 82820 %call58 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp55, ptr %tmp56)2821 %tmp59 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_42", align 82822 %call6110 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call548, ptr %tmp59, ptr %call58)2823 %tmp15 = call ptr @llvm.objc.retain(ptr %call6110) nounwind2824 call void @llvm.objc.release(ptr %call137) nounwind2825 %tmp64 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_46", align 82826 %call66 = call signext i8 @objc_msgSend(ptr %call6110, ptr %tmp64, ptr @_unnamed_cfstring_44)2827 %tobool67 = icmp eq i8 %call66, 02828 br i1 %tobool67, label %if.end74, label %if.then682829 2830if.then68: ; preds = %if.then442831 %tmp70 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_48", align 82832 %call7220 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call6110, ptr %tmp70)2833 %tmp16 = call ptr @llvm.objc.retain(ptr %call7220) nounwind2834 call void @llvm.objc.release(ptr %call6110) nounwind2835 br label %if.end742836 2837if.end74: ; preds = %if.then68, %if.then442838 %filename.0.in = phi ptr [ %call7220, %if.then68 ], [ %call6110, %if.then44 ]2839 %tmp17 = load ptr, ptr @"\01l_objc_msgSend_fixup_isEqual_", align 162840 %call78 = call signext i8 (ptr, ptr, ptr, ...) %tmp17(ptr %call137, ptr @"\01l_objc_msgSend_fixup_isEqual_", ptr %filename.0.in)2841 %tobool79 = icmp eq i8 %call78, 02842 br i1 %tobool79, label %land.lhs.true80, label %if.then1092843 2844land.lhs.true80: ; preds = %if.end742845 %tmp82 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_25", align 82846 %call84 = call signext i8 @objc_msgSend(ptr %filename.0.in, ptr %tmp82)2847 %tobool86 = icmp eq i8 %call84, 02848 br i1 %tobool86, label %if.then109, label %if.end1062849 2850if.end106: ; preds = %land.lhs.true802851 %tmp88 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_26", align 82852 %tmp90 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_28", align 82853 %call9218 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp88, ptr %tmp90, ptr %filename.0.in)2854 %tmp21 = call ptr @llvm.objc.retain(ptr %call9218) nounwind2855 call void @llvm.objc.release(ptr %url.025) nounwind2856 %tmp94 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_29", align 82857 %tmp95 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_31", align 82858 %call97 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp94, ptr %tmp95)2859 %tmp99 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_33", align 82860 %call10119 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call97, ptr %tmp99, ptr %call9218, i32 signext 1, ptr %err)2861 %phitmp = icmp eq ptr %call10119, null2862 br i1 %phitmp, label %if.then109, label %end2863 2864if.then109: ; preds = %if.end106, %land.lhs.true80, %if.end742865 %url.129 = phi ptr [ %call9218, %if.end106 ], [ %url.025, %if.end74 ], [ %url.025, %land.lhs.true80 ]2866 %tmp110 = load ptr, ptr %err, align 82867 %tobool111 = icmp eq ptr %tmp110, null2868 br i1 %tobool111, label %if.then112, label %if.end1252869 2870if.then112: ; preds = %if.then1092871 %tmp113 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_50", align 82872 %tmp114 = load ptr, ptr @NSCocoaErrorDomain, align 82873 %tmp115 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_51", align 82874 %call117 = call ptr @truncatedString(ptr %filename.0.in, i64 1034)2875 %tmp118 = load ptr, ptr @NSFilePathErrorKey, align 82876 %tmp119 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_53", align 82877 %call12113 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp115, ptr %tmp119, ptr %call117, ptr %tmp118, ptr null)2878 %tmp122 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_55", align 82879 %call12414 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp113, ptr %tmp122, ptr %tmp114, i64 258, ptr %call12113)2880 %tmp23 = call ptr @llvm.objc.retain(ptr %call12414) nounwind2881 %tmp25 = call ptr @llvm.objc.autorelease(ptr %tmp23) nounwind2882 store ptr %tmp25, ptr %err, align 82883 br label %if.end1252884 2885if.end125: ; preds = %if.then112, %if.then1092886 %tmp127 = phi ptr [ %tmp110, %if.then109 ], [ %tmp25, %if.then112 ]2887 %tmp126 = load ptr, ptr @"\01L_OBJC_CLASSLIST_REFERENCES_$_56", align 82888 %tmp128 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_58", align 82889 %call13015 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %tmp126, ptr %tmp128, ptr %tmp127)2890 %tmp131 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_60", align 82891 %call13317 = call ptr (ptr, ptr, ...) @objc_msgSend(ptr %call13015, ptr %tmp131)2892 br label %end2893 2894end: ; preds = %if.end125, %if.end106, %if.end, %land.lhs.true, %entry2895 %filename.2 = phi ptr [ %filename.0.in, %if.end106 ], [ %filename.0.in, %if.end125 ], [ %call137, %land.lhs.true ], [ null, %entry ], [ %call137, %if.end ]2896 %origFilename.0 = phi ptr [ %call137, %if.end106 ], [ %call137, %if.end125 ], [ %call137, %land.lhs.true ], [ null, %entry ], [ %call137, %if.end ]2897 %url.2 = phi ptr [ %call9218, %if.end106 ], [ %url.129, %if.end125 ], [ null, %land.lhs.true ], [ null, %entry ], [ %call2822, %if.end ]2898 call void @llvm.objc.release(ptr %tmp9) nounwind, !clang.imprecise_release !02899 call void @llvm.objc.release(ptr %url.2) nounwind, !clang.imprecise_release !02900 call void @llvm.objc.release(ptr %origFilename.0) nounwind, !clang.imprecise_release !02901 call void @llvm.objc.release(ptr %filename.2) nounwind, !clang.imprecise_release !02902 call void @llvm.objc.release(ptr %self) nounwind, !clang.imprecise_release !02903 ret void2904}2905 2906declare i32 @__gxx_personality_v0(...)2907 2908declare i32 @llvm.objc.sync.enter(ptr)2909declare i32 @llvm.objc.sync.exit(ptr)2910 2911; Make sure that we understand that objc_sync_{enter,exit} are IC_User not2912; IC_Call/IC_CallOrUser.2913 2914; CHECK-LABEL: define void @test67(2915; CHECK-NEXT: call i32 @llvm.objc.sync.enter(ptr %x)2916; CHECK-NEXT: call i32 @llvm.objc.sync.exit(ptr %x)2917; CHECK-NEXT: ret void2918; CHECK-NEXT: }2919define void @test67(ptr %x) {2920 call ptr @llvm.objc.retain(ptr %x)2921 call i32 @llvm.objc.sync.enter(ptr %x)2922 call i32 @llvm.objc.sync.exit(ptr %x)2923 call void @llvm.objc.release(ptr %x), !clang.imprecise_release !02924 ret void2925}2926 2927; CHECK-LABEL: define void @test68(2928; CHECK-NOT: call2929; CHECK: call void @callee2(2930; CHECK-NOT: call2931; CHECK: ret void2932 2933define void @test68(ptr %a, ptr %b) {2934 call ptr @llvm.objc.retain(ptr %a)2935 call ptr @llvm.objc.retain(ptr %b)2936 call void @callee2(ptr %a, ptr %b)2937 call void @llvm.objc.release(ptr %b), !clang.imprecise_release !02938 call void @llvm.objc.release(ptr %a), !clang.imprecise_release !02939 ret void2940}2941 2942!llvm.module.flags = !{!1}2943!llvm.dbg.cu = !{!3}2944 2945!0 = !{}2946!1 = !{i32 1, !"Debug Info Version", i32 3}2947!2 = distinct !DISubprogram(unit: !3)2948!3 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang",2949 file: !4,2950 isOptimized: true, flags: "-O2",2951 splitDebugFilename: "abc.debug", emissionKind: 2)2952!4 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")2953!5 = !{i32 2, !"Debug Info Version", i32 3}2954 2955; CHECK: attributes [[NUW]] = { nounwind }2956; CHECK: ![[RELEASE]] = !{}2957