1; RUN: opt -objc-arc -S < %s | FileCheck %s 2 3target datalayout = "e-p:64:64:64" 4 5declare i8* @objc_retain(i8*) 6declare i8* @objc_retainAutoreleasedReturnValue(i8*) 7declare void @objc_release(i8*) 8declare i8* @objc_autorelease(i8*) 9declare i8* @objc_autoreleaseReturnValue(i8*) 10declare i8* @objc_retainAutoreleaseReturnValue(i8*) 11declare void @objc_autoreleasePoolPop(i8*) 12declare void @objc_autoreleasePoolPush() 13declare i8* @objc_retainBlock(i8*) 14 15declare i8* @objc_retainedObject(i8*) 16declare i8* @objc_unretainedObject(i8*) 17declare i8* @objc_unretainedPointer(i8*) 18 19declare void @use_pointer(i8*) 20declare void @callee() 21declare void @callee_fnptr(void ()*) 22declare void @invokee() 23declare 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: } 39define void @test0(i1 %p) nounwind { 40entry: 41 %x = call i8* @returner() 42 %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %x) 43 br i1 %p, label %t, label %return 44 45t: 46 call void @use_pointer(i8* %x) 47 store i8 0, i8* %x 48 br label %return 49 50return: 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: } 60define 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 73define i8* @test3() { 74entry: 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 87define i8* @test4() { 88entry: 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) 120define 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) 131define 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) 144define 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) 154define 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 165define 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 179define 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 193define 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 206define 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 220define 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 232define 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 245define 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 257define 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 270define 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 281define 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 293define 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 305define 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 317define 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 327define void @test23(i8* %p) { 328 store i8 0, i8* %p 329 call i8* @objc_autoreleaseReturnValue(i8* %p) 330 ret void 331} 332 333; Don't convert autoreleaseRV to autorelease if the result is returned, 334; even through a bitcast. 335 336; CHECK: define {}* @test24( 337; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) 338define {}* @test24(i8* %p) { 339 %t = call i8* @objc_autoreleaseReturnValue(i8* %p) 340 %s = bitcast i8* %p to {}* 341 ret {}* %s 342} 343