1; RUN: opt -objc-arc -S < %s | FileCheck %s 2 3declare void @objc_release(i8* %x) 4declare i8* @objc_retain(i8* %x) 5declare i8* @objc_autorelease(i8* %x) 6declare i8* @objc_autoreleaseReturnValue(i8* %x) 7declare i8* @objc_retainAutoreleasedReturnValue(i8* %x) 8declare i8* @tmp(i8*) 9 10; Never tail call objc_autorelease. 11 12; CHECK: define i8* @test0(i8* %x) [[NUW:#[0-9]+]] { 13; CHECK: %tmp0 = call i8* @objc_autorelease(i8* %x) [[NUW]] 14; CHECK: %tmp1 = call i8* @objc_autorelease(i8* %x) [[NUW]] 15; CHECK: } 16define i8* @test0(i8* %x) nounwind { 17entry: 18 %tmp0 = call i8* @objc_autorelease(i8* %x) 19 %tmp1 = tail call i8* @objc_autorelease(i8* %x) 20 21 ret i8* %x 22} 23 24; Always tail call autoreleaseReturnValue. 25 26; CHECK: define i8* @test1(i8* %x) [[NUW]] { 27; CHECK: %tmp0 = tail call i8* @objc_autoreleaseReturnValue(i8* %x) [[NUW]] 28; CHECK: %tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x) [[NUW]] 29; CHECK: } 30define i8* @test1(i8* %x) nounwind { 31entry: 32 %tmp0 = call i8* @objc_autoreleaseReturnValue(i8* %x) 33 %tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x) 34 ret i8* %x 35} 36 37; Always tail call objc_retain. 38 39; CHECK: define i8* @test2(i8* %x) [[NUW]] { 40; CHECK: %tmp0 = tail call i8* @objc_retain(i8* %x) [[NUW]] 41; CHECK: %tmp1 = tail call i8* @objc_retain(i8* %x) [[NUW]] 42; CHECK: } 43define i8* @test2(i8* %x) nounwind { 44entry: 45 %tmp0 = call i8* @objc_retain(i8* %x) 46 %tmp1 = tail call i8* @objc_retain(i8* %x) 47 ret i8* %x 48} 49 50; Always tail call objc_retainAutoreleasedReturnValue. 51; CHECK: define i8* @test3(i8* %x) [[NUW]] { 52; CHECK: %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]] 53; CHECK: %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %z) [[NUW]] 54; CHECK: } 55define i8* @test3(i8* %x) nounwind { 56entry: 57 %y = call i8* @tmp(i8* %x) 58 %tmp0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %y) 59 %z = call i8* @tmp(i8* %x) 60 %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %z) 61 ret i8* %x 62} 63 64; By itself, we should never change whether or not objc_release is tail called. 65 66; CHECK: define void @test4(i8* %x) [[NUW]] { 67; CHECK: call void @objc_release(i8* %x) [[NUW]] 68; CHECK: tail call void @objc_release(i8* %x) [[NUW]] 69; CHECK: } 70define void @test4(i8* %x) nounwind { 71entry: 72 call void @objc_release(i8* %x) 73 tail call void @objc_release(i8* %x) 74 ret void 75} 76 77; If we convert a tail called @objc_autoreleaseReturnValue to an 78; @objc_autorelease, ensure that the tail call is removed. 79; CHECK: define i8* @test5(i8* %x) [[NUW]] { 80; CHECK: %tmp0 = call i8* @objc_autorelease(i8* %x) [[NUW]] 81; CHECK: } 82define i8* @test5(i8* %x) nounwind { 83entry: 84 %tmp0 = tail call i8* @objc_autoreleaseReturnValue(i8* %x) 85 ret i8* %tmp0 86} 87 88; CHECK: attributes [[NUW]] = { nounwind } 89 90