xref: /llvm-project/llvm/test/Transforms/ObjCARC/tail-call-invariant-enforcement.ll (revision 01e4f41b43b57dee751146fde9992c660bd7c714)
1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
2
3declare void @llvm.objc.release(ptr %x)
4declare ptr @llvm.objc.retain(ptr %x)
5declare ptr @llvm.objc.autorelease(ptr %x)
6declare ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
7declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %x)
8declare ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %x)
9declare ptr @tmp(ptr)
10
11; Never tail call objc_autorelease.
12
13; CHECK: define ptr @test0(ptr %x) [[NUW:#[0-9]+]] {
14; CHECK: %tmp0 = call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
15; CHECK: %tmp1 = call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
16; CHECK: }
17define ptr @test0(ptr %x) nounwind {
18entry:
19  %tmp0 = call ptr @llvm.objc.autorelease(ptr %x)
20  %tmp1 = tail call ptr @llvm.objc.autorelease(ptr %x)
21
22  ret ptr %x
23}
24
25; Always tail call autoreleaseReturnValue.
26
27; CHECK: define ptr @test1(ptr %x) [[NUW]] {
28; CHECK: %tmp0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) [[NUW]]
29; CHECK: %tmp1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) [[NUW]]
30; CHECK: }
31define ptr @test1(ptr %x) nounwind {
32entry:
33  %tmp0 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
34  %tmp1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
35  ret ptr %x
36}
37
38; Always tail call objc_retain.
39
40; CHECK: define ptr @test2(ptr %x) [[NUW]] {
41; CHECK: %tmp0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
42; CHECK: %tmp1 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
43; CHECK: }
44define ptr @test2(ptr %x) nounwind {
45entry:
46  %tmp0 = call ptr @llvm.objc.retain(ptr %x)
47  %tmp1 = tail call ptr @llvm.objc.retain(ptr %x)
48  ret ptr %x
49}
50
51; Always tail call objc_retainAutoreleasedReturnValue unless it's annotated with
52; notail.
53; CHECK: define ptr @test3(ptr %x) [[NUW]] {
54; CHECK: %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y) [[NUW]]
55; CHECK: %tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z) [[NUW]]
56; CHECK: %tmp2 = notail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z2) [[NUW]]
57; CHECK: }
58define ptr @test3(ptr %x) nounwind {
59entry:
60  %y = call ptr @tmp(ptr %x)
61  %tmp0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y)
62  %z = call ptr @tmp(ptr %x)
63  %tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
64  %z2 = call ptr @tmp(ptr %x)
65  %tmp2 = notail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z2)
66  ret ptr %x
67}
68
69; By itself, we should never change whether or not objc_release is tail called.
70
71; CHECK: define void @test4(ptr %x) [[NUW]] {
72; CHECK: call void @llvm.objc.release(ptr %x) [[NUW]]
73; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]]
74; CHECK: }
75define void @test4(ptr %x) nounwind {
76entry:
77  call void @llvm.objc.release(ptr %x)
78  tail call void @llvm.objc.release(ptr %x)
79  ret void
80}
81
82; If we convert a tail called @llvm.objc.autoreleaseReturnValue to an
83; @llvm.objc.autorelease, ensure that the tail call is removed.
84; CHECK: define ptr @test5(ptr %x) [[NUW]] {
85; CHECK: %tmp0 = call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
86; CHECK: }
87define ptr @test5(ptr %x) nounwind {
88entry:
89  %tmp0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
90  ret ptr %tmp0
91}
92
93; Always tail call llvm.objc.unsafeClaimAutoreleasedReturnValue.
94; CHECK: define ptr @test6(ptr %x) [[NUW]] {
95; CHECK: %tmp0 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %y) [[NUW]]
96; CHECK: %tmp1 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %z) [[NUW]]
97; CHECK: }
98define ptr @test6(ptr %x) nounwind {
99entry:
100  %y = call ptr @tmp(ptr %x)
101  %tmp0 = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %y)
102  %z = call ptr @tmp(ptr %x)
103  %tmp1 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %z)
104  ret ptr %x
105}
106
107; CHECK: attributes [[NUW]] = { nounwind }
108
109