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: 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) nounwind 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: 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: 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: 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: 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* %t) 125 ret i8* %t 126 } 127 128 ; CHECK: 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* %t 137 } 138 139 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand 140 ; is a return value. 141 142 ; CHECK: define void @test8() 143 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 144 define void @test8() { 145 %p = call i8* @returner() 146 call i8* @objc_retain(i8* %p) 147 ret void 148 } 149 150 ; Don't apply the RV optimization to autorelease if there's no retain. 151 152 ; CHECK: define i8* @test9(i8* %p) 153 ; CHECK: tail call i8* @objc_autorelease(i8* %p) 154 define i8* @test9(i8* %p) { 155 call i8* @objc_autorelease(i8* %p) 156 ret i8* %p 157 } 158 159 ; Apply the RV optimization. 160 161 ; CHECK: define i8* @test10(i8* %p) 162 ; CHECK: tail call i8* @objc_retain(i8* %p) nounwind 163 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind 164 ; CHECK-NEXT: ret i8* %p 165 define i8* @test10(i8* %p) { 166 %1 = call i8* @objc_retain(i8* %p) 167 %2 = call i8* @objc_autorelease(i8* %p) 168 ret i8* %p 169 } 170 171 ; Don't do the autoreleaseRV optimization because @use_pointer 172 ; could undo the retain. 173 174 ; CHECK: define i8* @test11(i8* %p) 175 ; CHECK: tail call i8* @objc_retain(i8* %p) 176 ; CHECK-NEXT: call void @use_pointer(i8* %p) 177 ; CHECK: tail call i8* @objc_autorelease(i8* %p) 178 ; CHECK-NEXT: ret i8* %p 179 define i8* @test11(i8* %p) { 180 %1 = call i8* @objc_retain(i8* %p) 181 call void @use_pointer(i8* %p) 182 %2 = call i8* @objc_autorelease(i8* %p) 183 ret i8* %p 184 } 185 186 ; Don't spoil the RV optimization. 187 188 ; CHECK: define i8* @test12(i8* %p) 189 ; CHECK: tail call i8* @objc_retain(i8* %p) 190 ; CHECK: call void @use_pointer(i8* %p) 191 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) 192 ; CHECK: ret i8* %p 193 define i8* @test12(i8* %p) { 194 %1 = call i8* @objc_retain(i8* %p) 195 call void @use_pointer(i8* %p) 196 %2 = call i8* @objc_autoreleaseReturnValue(i8* %p) 197 ret i8* %p 198 } 199 200 ; Don't zap the objc_retainAutoreleasedReturnValue. 201 202 ; CHECK: define i8* @test13( 203 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 204 ; CHECK: tail call i8* @objc_autorelease(i8* %p) 205 ; CHECK: ret i8* %p 206 define i8* @test13() { 207 %p = call i8* @returner() 208 %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 209 call void @callee() 210 %2 = call i8* @objc_autorelease(i8* %p) 211 ret i8* %p 212 } 213 214 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its 215 ; argument is not a return value. 216 217 ; CHECK: define void @test14( 218 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) nounwind 219 ; CHECK-NEXT: ret void 220 define void @test14(i8* %p) { 221 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 222 ret void 223 } 224 225 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its 226 ; argument is a return value. 227 228 ; CHECK: define void @test15( 229 ; CHECK-NEXT: %y = call i8* @returner() 230 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind 231 ; CHECK-NEXT: ret void 232 define void @test15() { 233 %y = call i8* @returner() 234 call i8* @objc_retainAutoreleasedReturnValue(i8* %y) 235 ret void 236 } 237 238 ; Convert objc_retain to objc_retainAutoreleasedReturnValue if its 239 ; argument is a return value. 240 241 ; CHECK: define void @test16( 242 ; CHECK-NEXT: %y = call i8* @returner() 243 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind 244 ; CHECK-NEXT: ret void 245 define void @test16() { 246 %y = call i8* @returner() 247 call i8* @objc_retain(i8* %y) 248 ret void 249 } 250 251 ; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its 252 ; argument is not a return value. 253 254 ; CHECK: define void @test17( 255 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind 256 ; CHECK-NEXT: ret void 257 define void @test17(i8* %y) { 258 call i8* @objc_retain(i8* %y) 259 ret void 260 } 261 262 ; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it 263 ; isn't next to the call providing its return value. 264 265 ; CHECK: define void @test18( 266 ; CHECK-NEXT: %y = call i8* @returner() 267 ; CHECK-NEXT: call void @callee() 268 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind 269 ; CHECK-NEXT: ret void 270 define void @test18() { 271 %y = call i8* @returner() 272 call void @callee() 273 call i8* @objc_retain(i8* %y) 274 ret void 275 } 276 277 ; Delete autoreleaseRV+retainRV pairs. 278 279 ; CHECK: define i8* @test19(i8* %p) { 280 ; CHECK-NEXT: ret i8* %p 281 define i8* @test19(i8* %p) { 282 call i8* @objc_autoreleaseReturnValue(i8* %p) 283 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 284 ret i8* %p 285 } 286 287 ; Like test19 but with plain autorelease. 288 289 ; CHECK: define i8* @test20(i8* %p) { 290 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p) 291 ; CHECK-NEXT: call i8* @objc_retain(i8* %p) 292 ; CHECK-NEXT: ret i8* %p 293 define i8* @test20(i8* %p) { 294 call i8* @objc_autorelease(i8* %p) 295 call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 296 ret i8* %p 297 } 298 299 ; Like test19 but with plain retain. 300 301 ; CHECK: define i8* @test21(i8* %p) { 302 ; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p) 303 ; CHECK-NEXT: call i8* @objc_retain(i8* %p) 304 ; CHECK-NEXT: ret i8* %p 305 define i8* @test21(i8* %p) { 306 call i8* @objc_autoreleaseReturnValue(i8* %p) 307 call i8* @objc_retain(i8* %p) 308 ret i8* %p 309 } 310 311 ; Like test19 but with plain retain and autorelease. 312 313 ; CHECK: define i8* @test22(i8* %p) { 314 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p) 315 ; CHECK-NEXT: call i8* @objc_retain(i8* %p) 316 ; CHECK-NEXT: ret i8* %p 317 define i8* @test22(i8* %p) { 318 call i8* @objc_autorelease(i8* %p) 319 call i8* @objc_retain(i8* %p) 320 ret i8* %p 321 } 322 323 ; Convert autoreleaseRV to autorelease. 324 325 ; CHECK: define void @test23( 326 ; CHECK: tail call i8* @objc_autorelease(i8* %p) nounwind 327 define void @test23(i8* %p) { 328 store i8 0, i8* %p 329 call i8* @objc_autoreleaseReturnValue(i8* %p) 330 ret void 331 } 332