Use references to attribute groups on the call/invoke instructions.
[oota-llvm.git] / test / Transforms / ObjCARC / contract.ll
1 ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
2
3 target datalayout = "e-p:64:64:64"
4
5 declare i8* @objc_retain(i8*)
6 declare void @objc_release(i8*)
7 declare i8* @objc_autorelease(i8*)
8 declare i8* @objc_autoreleaseReturnValue(i8*)
9 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
10
11 declare void @use_pointer(i8*)
12 declare i8* @returner()
13
14 ; CHECK: define void @test0
15 ; CHECK: call void @use_pointer(i8* %0)
16 ; CHECK: }
17 define void @test0(i8* %x) nounwind {
18 entry:
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: }
27 define void @test1(i8* %x) nounwind {
28 entry:
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: }
39 define void @test2(i8* %x) nounwind {
40 entry:
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: }
52 define i8* @test2b(i8* %x) nounwind {
53 entry:
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: }
65 define void @test3(i8* %x, i64 %n) {
66 entry:
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: }
83 define void @test4(i8* %x, i64 %n) {
84 entry:
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: }
99 define void @test5(i8* %p, i1 %a) {
100 entry:
101   tail call i8* @objc_retain(i8* %p) nounwind
102   br i1 %a, label %true, label %false
103
104 true:
105   call i8* @objc_autorelease(i8* %p) nounwind
106   call void @use_pointer(i8* %p)
107   ret void
108
109 false:
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: }
125 define 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
140 define 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: }
152 define i8* @test8(i1 %x, i8* %c) {
153 entry:
154   br i1 %x, label %return, label %if.then
155
156 if.then:                                          ; preds = %entry
157   %p = call i8* @objc_retain(i8* %c) nounwind
158   br label %return
159
160 return:                                           ; preds = %if.then, %entry
161   %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
162   ret i8* %retval
163 }
164
165 ; CHECK: attributes [[NUW]] = { nounwind }