contract.ll revision 351b7a10e2560a835759748c58da09e53207b39d
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()
13
14; CHECK: define void @test0
15; CHECK: call void @use_pointer(i8* %0)
16; CHECK: }
17define void @test0(i8* %x) nounwind {
18entry:
19  %0 = call i8* @objc_retain(i8* %x) nounwind
20  call void @use_pointer(i8* %x)
21  ret void
22}
23
24; CHECK: define void @test1
25; CHECK: call void @use_pointer(i8* %0)
26; CHECK: }
27define void @test1(i8* %x) nounwind {
28entry:
29  %0 = call i8* @objc_autorelease(i8* %x) nounwind
30  call void @use_pointer(i8* %x)
31  ret void
32}
33
34; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
35
36; CHECK: define void @test2(
37; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW:#[0-9]+]]
38; CHECK: }
39define void @test2(i8* %x) nounwind {
40entry:
41  %0 = tail call i8* @objc_retain(i8* %x) nounwind
42  call i8* @objc_autorelease(i8* %0) nounwind
43  call void @use_pointer(i8* %x)
44  ret void
45}
46
47; Same as test2 but the value is returned. Do an RV optimization.
48
49; CHECK: define i8* @test2b(
50; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) [[NUW]]
51; CHECK: }
52define i8* @test2b(i8* %x) nounwind {
53entry:
54  %0 = tail call i8* @objc_retain(i8* %x) nounwind
55  tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
56  ret i8* %x
57}
58
59; Merge a retain,autorelease pair around a call.
60
61; CHECK: define void @test3(
62; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW]]
63; CHECK: @use_pointer(i8* %0)
64; CHECK: }
65define void @test3(i8* %x, i64 %n) {
66entry:
67  tail call i8* @objc_retain(i8* %x) nounwind
68  call void @use_pointer(i8* %x)
69  call i8* @objc_autorelease(i8* %x) nounwind
70  ret void
71}
72
73; Trivial retain,autorelease pair with intervening call, but it's post-dominated
74; by another release. The retain and autorelease can be merged.
75
76; CHECK: define void @test4(
77; CHECK-NEXT: entry:
78; CHECK-NEXT: @objc_retainAutorelease(i8* %x) [[NUW]]
79; CHECK-NEXT: @use_pointer
80; CHECK-NEXT: @objc_release
81; CHECK-NEXT: ret void
82; CHECK-NEXT: }
83define void @test4(i8* %x, i64 %n) {
84entry:
85  tail call i8* @objc_retain(i8* %x) nounwind
86  call void @use_pointer(i8* %x)
87  call i8* @objc_autorelease(i8* %x) nounwind
88  tail call void @objc_release(i8* %x) nounwind
89  ret void
90}
91
92; Don't merge retain and autorelease if they're not control-equivalent.
93
94; CHECK: define void @test5(
95; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
96; CHECK: true:
97; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]]
98; CHECK: }
99define void @test5(i8* %p, i1 %a) {
100entry:
101  tail call i8* @objc_retain(i8* %p) nounwind
102  br i1 %a, label %true, label %false
103
104true:
105  call i8* @objc_autorelease(i8* %p) nounwind
106  call void @use_pointer(i8* %p)
107  ret void
108
109false:
110  ret void
111}
112
113; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
114; an objc_autorelease.
115; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
116; objc_retainAutoreleasedReturnValueAutorelease and merge
117; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
118; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
119; Those entrypoints don't exist yet though.
120
121; CHECK: define i8* @test6(
122; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) [[NUW]]
123; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) [[NUW]]
124; CHECK: }
125define i8* @test6() {
126  %p = call i8* @returner()
127  tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
128  %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
129  call void @use_pointer(i8* %t)
130  ret i8* %t
131}
132
133; Don't spoil the RV optimization.
134
135; CHECK: define i8* @test7(i8* %p)
136; CHECK: tail call i8* @objc_retain(i8* %p)
137; CHECK: call void @use_pointer(i8* %1)
138; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1)
139; CHECK: ret i8* %2
140define i8* @test7(i8* %p) {
141  %1 = tail call i8* @objc_retain(i8* %p)
142  call void @use_pointer(i8* %p)
143  %2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
144  ret i8* %p
145}
146
147; Do the return value substitution for PHI nodes too.
148
149; CHECK: define i8* @test8(
150; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ]
151; CHECK: }
152define i8* @test8(i1 %x, i8* %c) {
153entry:
154  br i1 %x, label %return, label %if.then
155
156if.then:                                          ; preds = %entry
157  %p = call i8* @objc_retain(i8* %c) nounwind
158  br label %return
159
160return:                                           ; preds = %if.then, %entry
161  %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
162  ret i8* %retval
163}
164
165; CHECK: attributes [[NUW]] = { nounwind }
166