1 ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s 2 3 target datalayout = "e-p:64:64:64" 4 5 declare i8* @objc_retain(i8*) 6 declare void @objc_release(i8*) 7 declare i8* @objc_autorelease(i8*) 8 declare i8* @objc_autoreleaseReturnValue(i8*) 9 declare i8* @objc_retainAutoreleasedReturnValue(i8*) 10 11 declare void @use_pointer(i8*) 12 declare i8* @returner() 13 14 ; CHECK: define void @test0 15 ; CHECK: call void @use_pointer(i8* %0) 16 ; CHECK: } 17 define void @test0(i8* %x) nounwind { 18 entry: 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: } 27 define void @test1(i8* %x) nounwind { 28 entry: 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: } 39 define void @test2(i8* %x) nounwind { 40 entry: 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: } 52 define i8* @test2b(i8* %x) nounwind { 53 entry: 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: } 65 define void @test3(i8* %x, i64 %n) { 66 entry: 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: } 83 define void @test4(i8* %x, i64 %n) { 84 entry: 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: } 99 define void @test5(i8* %p, i1 %a) { 100 entry: 101 tail call i8* @objc_retain(i8* %p) nounwind 102 br i1 %a, label %true, label %false 103 104 true: 105 call i8* @objc_autorelease(i8* %p) nounwind 106 call void @use_pointer(i8* %p) 107 ret void 108 109 false: 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: } 125 define 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 140 define 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: } 152 define i8* @test8(i1 %x, i8* %c) { 153 entry: 154 br i1 %x, label %return, label %if.then 155 156 if.then: ; preds = %entry 157 %p = call i8* @objc_retain(i8* %c) nounwind 158 br label %return 159 160 return: ; 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