1; RUN: opt -objc-arc-contract -S < %s | FileCheck %s 2 3target datalayout = "e-p:64:64:64" 4 5declare i8* @objc_retain(i8*) 6declare void @objc_release(i8*) 7declare i8* @objc_autorelease(i8*) 8declare i8* @objc_autoreleaseReturnValue(i8*) 9declare i8* @objc_retainAutoreleasedReturnValue(i8*) 10 11declare void @use_pointer(i8*) 12declare i8* @returner() 13 14; CHECK: define void @test0 15; CHECK: call void @use_pointer(i8* %0) 16; CHECK: } 17define void @test0(i8* %x) nounwind { 18entry: 19 %0 = call i8* @objc_retain(i8* %x) nounwind 20 call void @use_pointer(i8* %x) 21 ret void 22} 23 24; CHECK: define void @test1 25; CHECK: call void @use_pointer(i8* %0) 26; CHECK: } 27define void @test1(i8* %x) nounwind { 28entry: 29 %0 = call i8* @objc_autorelease(i8* %x) nounwind 30 call void @use_pointer(i8* %x) 31 ret void 32} 33 34; Merge objc_retain and objc_autorelease into objc_retainAutorelease. 35 36; CHECK: define void @test2( 37; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW:#[0-9]+]] 38; CHECK: } 39define void @test2(i8* %x) nounwind { 40entry: 41 %0 = tail call i8* @objc_retain(i8* %x) nounwind 42 call i8* @objc_autorelease(i8* %0) nounwind 43 call void @use_pointer(i8* %x) 44 ret void 45} 46 47; Same as test2 but the value is returned. Do an RV optimization. 48 49; CHECK: define i8* @test2b( 50; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) [[NUW]] 51; CHECK: } 52define i8* @test2b(i8* %x) nounwind { 53entry: 54 %0 = tail call i8* @objc_retain(i8* %x) nounwind 55 tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind 56 ret i8* %x 57} 58 59; Merge a retain,autorelease pair around a call. 60 61; CHECK: define void @test3( 62; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW]] 63; CHECK: @use_pointer(i8* %0) 64; CHECK: } 65define void @test3(i8* %x, i64 %n) { 66entry: 67 tail call i8* @objc_retain(i8* %x) nounwind 68 call void @use_pointer(i8* %x) 69 call i8* @objc_autorelease(i8* %x) nounwind 70 ret void 71} 72 73; Trivial retain,autorelease pair with intervening call, but it's post-dominated 74; by another release. The retain and autorelease can be merged. 75 76; CHECK: define void @test4( 77; CHECK-NEXT: entry: 78; CHECK-NEXT: @objc_retainAutorelease(i8* %x) [[NUW]] 79; CHECK-NEXT: @use_pointer 80; CHECK-NEXT: @objc_release 81; CHECK-NEXT: ret void 82; CHECK-NEXT: } 83define void @test4(i8* %x, i64 %n) { 84entry: 85 tail call i8* @objc_retain(i8* %x) nounwind 86 call void @use_pointer(i8* %x) 87 call i8* @objc_autorelease(i8* %x) nounwind 88 tail call void @objc_release(i8* %x) nounwind 89 ret void 90} 91 92; Don't merge retain and autorelease if they're not control-equivalent. 93 94; CHECK: define void @test5( 95; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]] 96; CHECK: true: 97; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]] 98; CHECK: } 99define void @test5(i8* %p, i1 %a) { 100entry: 101 tail call i8* @objc_retain(i8* %p) nounwind 102 br i1 %a, label %true, label %false 103 104true: 105 call i8* @objc_autorelease(i8* %p) nounwind 106 call void @use_pointer(i8* %p) 107 ret void 108 109false: 110 ret void 111} 112 113; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into 114; an objc_autorelease. 115; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into 116; objc_retainAutoreleasedReturnValueAutorelease and merge 117; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue 118; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue? 119; Those entrypoints don't exist yet though. 120 121; CHECK: define i8* @test6( 122; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) [[NUW]] 123; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) [[NUW]] 124; CHECK: } 125define i8* @test6() { 126 %p = call i8* @returner() 127 tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind 128 %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind 129 call void @use_pointer(i8* %t) 130 ret i8* %t 131} 132 133; Don't spoil the RV optimization. 134 135; CHECK: define i8* @test7(i8* %p) 136; CHECK: tail call i8* @objc_retain(i8* %p) 137; CHECK: call void @use_pointer(i8* %1) 138; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1) 139; CHECK: ret i8* %2 140define i8* @test7(i8* %p) { 141 %1 = tail call i8* @objc_retain(i8* %p) 142 call void @use_pointer(i8* %p) 143 %2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p) 144 ret i8* %p 145} 146 147; Do the return value substitution for PHI nodes too. 148 149; CHECK: define i8* @test8( 150; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ] 151; CHECK: } 152define i8* @test8(i1 %x, i8* %c) { 153entry: 154 br i1 %x, label %return, label %if.then 155 156if.then: ; preds = %entry 157 %p = call i8* @objc_retain(i8* %c) nounwind 158 br label %return 159 160return: ; preds = %if.then, %entry 161 %retval = phi i8* [ %c, %if.then ], [ null, %entry ] 162 ret i8* %retval 163} 164 165; CHECK: attributes [[NUW]] = { nounwind } 166