1 ; RUN: opt -objc-arc -S < %s | FileCheck %s 2 3 target datalayout = "e-p:64:64:64" 4 5 declare i8* @objc_retain(i8*) 6 declare i8* @objc_retainAutoreleasedReturnValue(i8*) 7 declare void @objc_release(i8*) 8 declare i8* @objc_autorelease(i8*) 9 declare i8* @objc_autoreleaseReturnValue(i8*) 10 declare i8* @objc_retainAutoreleaseReturnValue(i8*) 11 declare void @objc_autoreleasePoolPop(i8*) 12 declare void @objc_autoreleasePoolPush() 13 declare i8* @objc_retainBlock(i8*) 14 15 declare i8* @objc_retainedObject(i8*) 16 declare i8* @objc_unretainedObject(i8*) 17 declare i8* @objc_unretainedPointer(i8*) 18 19 declare void @use_pointer(i8*) 20 declare void @callee() 21 declare void @callee_fnptr(void ()*) 22 declare void @invokee() 23 declare i8* @returner() 24 25 ; Test that retain+release elimination is suppressed when the 26 ; retain is an objc_retainAutoreleasedReturnValue, since it's 27 ; better to do the RV optimization. 28 29 ; CHECK-LABEL: define void @test0( 30 ; CHECK-NEXT: entry: 31 ; CHECK-NEXT: %x = call i8* @returner 32 ; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %x) [[NUW:#[0-9]+]] 33 ; CHECK: t: 34 ; CHECK-NOT: @objc_ 35 ; CHECK: return: 36 ; CHECK-NEXT: call void @objc_release(i8* %x) 37 ; CHECK-NEXT: ret void 38 ; CHECK-NEXT: } 39 define void @test0(i1 %p) nounwind { 40 entry: 41 %x = call i8* @returner() 42 %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %x) 43 br i1 %p, label %t, label %return 44 45 t: 46 call void @use_pointer(i8* %x) 47 store i8 0, i8* %x 48 br label %return 49 50 return: 51 call void @objc_release(i8* %x) nounwind 52 ret void 53 } 54 55 ; Delete no-ops. 56 57 ; CHECK-LABEL: define void @test2( 58 ; CHECK-NOT: @objc_ 59 ; CHECK: } 60 define void @test2() { 61 call i8* @objc_retainAutoreleasedReturnValue(i8* null) 62 call i8* @objc_autoreleaseReturnValue(i8* null) 63 ; call i8* @objc_retainAutoreleaseReturnValue(i8* null) ; TODO 64 ret void 65 } 66 67 ; Delete a redundant retainRV,autoreleaseRV when forwaring a call result 68 ; directly to a return value. 69 70 ; CHECK-LABEL: define i8* @test3( 71 ; CHECK: call i8* @returner() 72 ; CHECK-NEXT: ret i8* %call 73 define i8* @test3() { 74 entry: 75 %call = call i8* @returner() 76 %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind 77 %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind 78 ret i8* %1 79 } 80 81 ; Delete a redundant retain,autoreleaseRV when forwaring a call result 82 ; directly to a return value. 83 84 ; CHECK-LABEL: define i8* @test4( 85 ; CHECK: call i8* @returner() 86 ; CHECK-NEXT: ret i8* %call 87 define i8* @test4() { 88 entry: 89 %call = call i8* @returner() 90 %0 = call i8* @objc_retain(i8* %call) nounwind 91 %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind 92 ret i8* %1 93 } 94 95 ; Delete a redundant fused retain+autoreleaseRV when forwaring a call result 96 ; directly to a return value. 97 98 ; TODO 99 ; HECK: define i8* @test5 100 ; HECK: call i8* @returner() 101 ; HECK-NEXT: ret i8* %call 102 ;define i8* @test5() { 103 ;entry: 104 ; %call = call i8* @returner() 105 ; %0 = call i8* @objc_retainAutoreleaseReturnValue(i8* %call) nounwind 106 ; ret i8* %0 107 ;} 108 109 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into 110 ; an objc_autorelease. 111 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into 112 ; objc_retainAutoreleasedReturnValueAutorelease and merge 113 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue 114 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue? 115 ; Those entrypoints don't exist yet though. 116 117 ; CHECK-LABEL: define i8* @test7( 118 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 119 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) 120 define i8* @test7() { 121 %p = call i8* @returner() 122 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 123 %t = call i8* @objc_autoreleaseReturnValue(i8* %p) 124 call void @use_pointer(i8* %p) 125 ret i8* %t 126 } 127 128 ; CHECK-LABEL: define i8* @test7b( 129 ; CHECK: call i8* @objc_retain(i8* %p) 130 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) 131 define i8* @test7b() { 132 %p = call i8* @returner() 133 call void @use_pointer(i8* %p) 134 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 135 %t = call i8* @objc_autoreleaseReturnValue(i8* %p) 136 ret i8* %p 137 } 138 139 ; Don't apply the RV optimization to autorelease if there's no retain. 140 141 ; CHECK: define i8* @test9(i8* %p) 142 ; CHECK: call i8* @objc_autorelease(i8* %p) 143 define i8* @test9(i8* %p) { 144 call i8* @objc_autorelease(i8* %p) 145 ret i8* %p 146 } 147 148 ; Do not apply the RV optimization. 149 150 ; CHECK: define i8* @test10(i8* %p) 151 ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]] 152 ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]] 153 ; CHECK-NEXT: ret i8* %p 154 define i8* @test10(i8* %p) { 155 %1 = call i8* @objc_retain(i8* %p) 156 %2 = call i8* @objc_autorelease(i8* %p) 157 ret i8* %p 158 } 159 160 ; Don't do the autoreleaseRV optimization because @use_pointer 161 ; could undo the retain. 162 163 ; CHECK: define i8* @test11(i8* %p) 164 ; CHECK: tail call i8* @objc_retain(i8* %p) 165 ; CHECK-NEXT: call void @use_pointer(i8* %p) 166 ; CHECK: call i8* @objc_autorelease(i8* %p) 167 ; CHECK-NEXT: ret i8* %p 168 define i8* @test11(i8* %p) { 169 %1 = call i8* @objc_retain(i8* %p) 170 call void @use_pointer(i8* %p) 171 %2 = call i8* @objc_autorelease(i8* %p) 172 ret i8* %p 173 } 174 175 ; Don't spoil the RV optimization. 176 177 ; CHECK: define i8* @test12(i8* %p) 178 ; CHECK: tail call i8* @objc_retain(i8* %p) 179 ; CHECK: call void @use_pointer(i8* %p) 180 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) 181 ; CHECK: ret i8* %p 182 define i8* @test12(i8* %p) { 183 %1 = call i8* @objc_retain(i8* %p) 184 call void @use_pointer(i8* %p) 185 %2 = call i8* @objc_autoreleaseReturnValue(i8* %p) 186 ret i8* %p 187 } 188 189 ; Don't zap the objc_retainAutoreleasedReturnValue. 190 191 ; CHECK-LABEL: define i8* @test13( 192 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 193 ; CHECK: call i8* @objc_autorelease(i8* %p) 194 ; CHECK: ret i8* %p 195 define i8* @test13() { 196 %p = call i8* @returner() 197 %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 198 call void @callee() 199 %2 = call i8* @objc_autorelease(i8* %p) 200 ret i8* %p 201 } 202 203 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its 204 ; argument is not a return value. 205 206 ; CHECK-LABEL: define void @test14( 207 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) [[NUW]] 208 ; CHECK-NEXT: ret void 209 define void @test14(i8* %p) { 210 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 211 ret void 212 } 213 214 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its 215 ; argument is a return value. 216 217 ; CHECK-LABEL: define void @test15( 218 ; CHECK-NEXT: %y = call i8* @returner() 219 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]] 220 ; CHECK-NEXT: ret void 221 define void @test15() { 222 %y = call i8* @returner() 223 call i8* @objc_retainAutoreleasedReturnValue(i8* %y) 224 ret void 225 } 226 227 ; Delete autoreleaseRV+retainRV pairs. 228 229 ; CHECK: define i8* @test19(i8* %p) { 230 ; CHECK-NEXT: ret i8* %p 231 define i8* @test19(i8* %p) { 232 call i8* @objc_autoreleaseReturnValue(i8* %p) 233 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 234 ret i8* %p 235 } 236 237 ; Like test19 but with plain autorelease. 238 239 ; CHECK: define i8* @test20(i8* %p) { 240 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p) 241 ; CHECK-NEXT: call i8* @objc_retain(i8* %p) 242 ; CHECK-NEXT: ret i8* %p 243 define i8* @test20(i8* %p) { 244 call i8* @objc_autorelease(i8* %p) 245 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 246 ret i8* %p 247 } 248 249 ; Like test19 but with plain retain. 250 251 ; CHECK: define i8* @test21(i8* %p) { 252 ; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p) 253 ; CHECK-NEXT: call i8* @objc_retain(i8* %p) 254 ; CHECK-NEXT: ret i8* %p 255 define i8* @test21(i8* %p) { 256 call i8* @objc_autoreleaseReturnValue(i8* %p) 257 call i8* @objc_retain(i8* %p) 258 ret i8* %p 259 } 260 261 ; Like test19 but with plain retain and autorelease. 262 263 ; CHECK: define i8* @test22(i8* %p) { 264 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p) 265 ; CHECK-NEXT: call i8* @objc_retain(i8* %p) 266 ; CHECK-NEXT: ret i8* %p 267 define i8* @test22(i8* %p) { 268 call i8* @objc_autorelease(i8* %p) 269 call i8* @objc_retain(i8* %p) 270 ret i8* %p 271 } 272 273 ; Convert autoreleaseRV to autorelease. 274 275 ; CHECK-LABEL: define void @test23( 276 ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]] 277 define void @test23(i8* %p) { 278 store i8 0, i8* %p 279 call i8* @objc_autoreleaseReturnValue(i8* %p) 280 ret void 281 } 282 283 ; Don't convert autoreleaseRV to autorelease if the result is returned, 284 ; even through a bitcast. 285 286 ; CHECK-LABEL: define {}* @test24( 287 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) 288 define {}* @test24(i8* %p) { 289 %t = call i8* @objc_autoreleaseReturnValue(i8* %p) 290 %s = bitcast i8* %p to {}* 291 ret {}* %s 292 } 293 294 ; CHECK: attributes [[NUW]] = { nounwind } 295