1; RUN: opt -objc-arc-contract -S < %s | FileCheck %s 2 3target datalayout = "e-p:64:64:64" 4 5declare i8* @objc_retain(i8*) 6declare void @objc_release(i8*) 7declare i8* @objc_autorelease(i8*) 8declare i8* @objc_autoreleaseReturnValue(i8*) 9declare i8* @objc_retainAutoreleasedReturnValue(i8*) 10 11declare void @use_pointer(i8*) 12declare i8* @returner() 13declare void @callee() 14 15; CHECK-LABEL: define void @test0( 16; CHECK: call void @use_pointer(i8* %0) 17; CHECK: } 18define void @test0(i8* %x) nounwind { 19entry: 20 %0 = call i8* @objc_retain(i8* %x) nounwind 21 call void @use_pointer(i8* %x) 22 ret void 23} 24 25; CHECK-LABEL: define void @test1( 26; CHECK: call void @use_pointer(i8* %0) 27; CHECK: } 28define void @test1(i8* %x) nounwind { 29entry: 30 %0 = call i8* @objc_autorelease(i8* %x) nounwind 31 call void @use_pointer(i8* %x) 32 ret void 33} 34 35; Merge objc_retain and objc_autorelease into objc_retainAutorelease. 36 37; CHECK-LABEL: define void @test2( 38; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW:#[0-9]+]] 39; CHECK: } 40define void @test2(i8* %x) nounwind { 41entry: 42 %0 = tail call i8* @objc_retain(i8* %x) nounwind 43 call i8* @objc_autorelease(i8* %0) nounwind 44 call void @use_pointer(i8* %x) 45 ret void 46} 47 48; Same as test2 but the value is returned. Do an RV optimization. 49 50; CHECK-LABEL: define i8* @test2b( 51; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) [[NUW]] 52; CHECK: } 53define i8* @test2b(i8* %x) nounwind { 54entry: 55 %0 = tail call i8* @objc_retain(i8* %x) nounwind 56 tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind 57 ret i8* %x 58} 59 60; Merge a retain,autorelease pair around a call. 61 62; CHECK-LABEL: define void @test3( 63; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW]] 64; CHECK: @use_pointer(i8* %0) 65; CHECK: } 66define void @test3(i8* %x, i64 %n) { 67entry: 68 tail call i8* @objc_retain(i8* %x) nounwind 69 call void @use_pointer(i8* %x) 70 call i8* @objc_autorelease(i8* %x) nounwind 71 ret void 72} 73 74; Trivial retain,autorelease pair with intervening call, but it's post-dominated 75; by another release. The retain and autorelease can be merged. 76 77; CHECK-LABEL: define void @test4( 78; CHECK-NEXT: entry: 79; CHECK-NEXT: @objc_retainAutorelease(i8* %x) [[NUW]] 80; CHECK-NEXT: @use_pointer 81; CHECK-NEXT: @objc_release 82; CHECK-NEXT: ret void 83; CHECK-NEXT: } 84define void @test4(i8* %x, i64 %n) { 85entry: 86 tail call i8* @objc_retain(i8* %x) nounwind 87 call void @use_pointer(i8* %x) 88 call i8* @objc_autorelease(i8* %x) nounwind 89 tail call void @objc_release(i8* %x) nounwind 90 ret void 91} 92 93; Don't merge retain and autorelease if they're not control-equivalent. 94 95; CHECK-LABEL: define void @test5( 96; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]] 97; CHECK: true: 98; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]] 99; CHECK: } 100define void @test5(i8* %p, i1 %a) { 101entry: 102 tail call i8* @objc_retain(i8* %p) nounwind 103 br i1 %a, label %true, label %false 104 105true: 106 call i8* @objc_autorelease(i8* %p) nounwind 107 call void @use_pointer(i8* %p) 108 ret void 109 110false: 111 ret void 112} 113 114; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into 115; an objc_autorelease. 116; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into 117; objc_retainAutoreleasedReturnValueAutorelease and merge 118; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue 119; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue? 120; Those entrypoints don't exist yet though. 121 122; CHECK-LABEL: define i8* @test6( 123; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) [[NUW]] 124; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) [[NUW]] 125; CHECK: } 126define i8* @test6() { 127 %p = call i8* @returner() 128 tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind 129 %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind 130 call void @use_pointer(i8* %t) 131 ret i8* %t 132} 133 134; Don't spoil the RV optimization. 135 136; CHECK: define i8* @test7(i8* %p) 137; CHECK: tail call i8* @objc_retain(i8* %p) 138; CHECK: call void @use_pointer(i8* %1) 139; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1) 140; CHECK: ret i8* %2 141; CHECK-NEXT: } 142define i8* @test7(i8* %p) { 143 %1 = tail call i8* @objc_retain(i8* %p) 144 call void @use_pointer(i8* %p) 145 %2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p) 146 ret i8* %p 147} 148 149; Do the return value substitution for PHI nodes too. 150 151; CHECK-LABEL: define i8* @test8( 152; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ] 153; CHECK: } 154define i8* @test8(i1 %x, i8* %c) { 155entry: 156 br i1 %x, label %return, label %if.then 157 158if.then: ; preds = %entry 159 %p = call i8* @objc_retain(i8* %c) nounwind 160 br label %return 161 162return: ; preds = %if.then, %entry 163 %retval = phi i8* [ %c, %if.then ], [ null, %entry ] 164 ret i8* %retval 165} 166 167; Kill calls to @clang.arc.use(...) 168; CHECK-LABEL: define void @test9( 169; CHECK-NOT: clang.arc.use 170; CHECK: } 171define void @test9(i8* %a, i8* %b) { 172 call void (...) @clang.arc.use(i8* %a, i8* %b) nounwind 173 ret void 174} 175 176 177; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand 178; is a return value. 179 180; CHECK: define void @test10() 181; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) 182define void @test10() { 183 %p = call i8* @returner() 184 tail call i8* @objc_retain(i8* %p) nounwind 185 ret void 186} 187 188; Convert objc_retain to objc_retainAutoreleasedReturnValue if its 189; argument is a return value. 190 191; CHECK-LABEL: define void @test11( 192; CHECK-NEXT: %y = call i8* @returner() 193; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]] 194; CHECK-NEXT: ret void 195define void @test11() { 196 %y = call i8* @returner() 197 tail call i8* @objc_retain(i8* %y) nounwind 198 ret void 199} 200 201; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its 202; argument is not a return value. 203 204; CHECK-LABEL: define void @test12( 205; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) [[NUW]] 206; CHECK-NEXT: ret void 207; CHECK-NEXT: } 208define void @test12(i8* %y) { 209 tail call i8* @objc_retain(i8* %y) nounwind 210 ret void 211} 212 213; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it 214; isn't next to the call providing its return value. 215 216; CHECK-LABEL: define void @test13( 217; CHECK-NEXT: %y = call i8* @returner() 218; CHECK-NEXT: call void @callee() 219; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) [[NUW]] 220; CHECK-NEXT: ret void 221; CHECK-NEXT: } 222define void @test13() { 223 %y = call i8* @returner() 224 call void @callee() 225 tail call i8* @objc_retain(i8* %y) nounwind 226 ret void 227} 228 229 230declare void @clang.arc.use(...) nounwind 231 232; CHECK: attributes [[NUW]] = { nounwind } 233