• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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* @objc_unsafeClaimAutoreleasedReturnValue(i8* %x)
9declare i8* @tmp(i8*)
10
11; Never tail call objc_autorelease.
12
13; CHECK: define i8* @test0(i8* %x) [[NUW:#[0-9]+]] {
14; CHECK: %tmp0 = call i8* @objc_autorelease(i8* %x) [[NUW]]
15; CHECK: %tmp1 = call i8* @objc_autorelease(i8* %x) [[NUW]]
16; CHECK: }
17define i8* @test0(i8* %x) nounwind {
18entry:
19  %tmp0 = call i8* @objc_autorelease(i8* %x)
20  %tmp1 = tail call i8* @objc_autorelease(i8* %x)
21
22  ret i8* %x
23}
24
25; Always tail call autoreleaseReturnValue.
26
27; CHECK: define i8* @test1(i8* %x) [[NUW]] {
28; CHECK: %tmp0 = tail call i8* @objc_autoreleaseReturnValue(i8* %x) [[NUW]]
29; CHECK: %tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x) [[NUW]]
30; CHECK: }
31define i8* @test1(i8* %x) nounwind {
32entry:
33  %tmp0 = call i8* @objc_autoreleaseReturnValue(i8* %x)
34  %tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
35  ret i8* %x
36}
37
38; Always tail call objc_retain.
39
40; CHECK: define i8* @test2(i8* %x) [[NUW]] {
41; CHECK: %tmp0 = tail call i8* @objc_retain(i8* %x) [[NUW]]
42; CHECK: %tmp1 = tail call i8* @objc_retain(i8* %x) [[NUW]]
43; CHECK: }
44define i8* @test2(i8* %x) nounwind {
45entry:
46  %tmp0 = call i8* @objc_retain(i8* %x)
47  %tmp1 = tail call i8* @objc_retain(i8* %x)
48  ret i8* %x
49}
50
51; Always tail call objc_retainAutoreleasedReturnValue.
52; CHECK: define i8* @test3(i8* %x) [[NUW]] {
53; CHECK: %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]]
54; CHECK: %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %z) [[NUW]]
55; CHECK: }
56define i8* @test3(i8* %x) nounwind {
57entry:
58  %y = call i8* @tmp(i8* %x)
59  %tmp0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
60  %z = call i8* @tmp(i8* %x)
61  %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
62  ret i8* %x
63}
64
65; By itself, we should never change whether or not objc_release is tail called.
66
67; CHECK: define void @test4(i8* %x) [[NUW]] {
68; CHECK: call void @objc_release(i8* %x) [[NUW]]
69; CHECK: tail call void @objc_release(i8* %x) [[NUW]]
70; CHECK: }
71define void @test4(i8* %x) nounwind {
72entry:
73  call void @objc_release(i8* %x)
74  tail call void @objc_release(i8* %x)
75  ret void
76}
77
78; If we convert a tail called @objc_autoreleaseReturnValue to an
79; @objc_autorelease, ensure that the tail call is removed.
80; CHECK: define i8* @test5(i8* %x) [[NUW]] {
81; CHECK: %tmp0 = call i8* @objc_autorelease(i8* %x) [[NUW]]
82; CHECK: }
83define i8* @test5(i8* %x) nounwind {
84entry:
85  %tmp0 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
86  ret i8* %tmp0
87}
88
89; Always tail call objc_unsafeClaimAutoreleasedReturnValue.
90; CHECK: define i8* @test6(i8* %x) [[NUW]] {
91; CHECK: %tmp0 = tail call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %y) [[NUW]]
92; CHECK: %tmp1 = tail call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %z) [[NUW]]
93; CHECK: }
94define i8* @test6(i8* %x) nounwind {
95entry:
96  %y = call i8* @tmp(i8* %x)
97  %tmp0 = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %y)
98  %z = call i8* @tmp(i8* %x)
99  %tmp1 = tail call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %z)
100  ret i8* %x
101}
102
103; CHECK: attributes [[NUW]] = { nounwind }
104
105