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-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: } 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-LABEL: 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-LABEL: 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-LABEL: 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-LABEL: 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* %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) 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* %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) 143define 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 154define 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 168define 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 182define 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 195define 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 209define 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 221define 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 231define 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 243define 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 255define 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 267define 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]] 277define 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) 288define {}* @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