Follow up to 168711: It's safe to base this analysis on the found compare, just retur...
[oota-llvm.git] / test / Transforms / ObjCARC / contract-storestrong.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 void @use_pointer(i8*)
8
9 @x = external global i8*
10
11 ; CHECK: define void @test0(
12 ; CHECK: entry:
13 ; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) nounwind
14 ; CHECK-NEXT: ret void
15 define void @test0(i8* %p) {
16 entry:
17   %0 = tail call i8* @objc_retain(i8* %p) nounwind
18   %tmp = load i8** @x, align 8
19   store i8* %0, i8** @x, align 8
20   tail call void @objc_release(i8* %tmp) nounwind
21   ret void
22 }
23
24 ; Don't do this if the load is volatile.
25
26 ;      CHECK: define void @test1(i8* %p) {
27 ; CHECK-NEXT: entry:
28 ; CHECK-NEXT:   %0 = tail call i8* @objc_retain(i8* %p) nounwind
29 ; CHECK-NEXT:   %tmp = load volatile i8** @x, align 8
30 ; CHECK-NEXT:   store i8* %0, i8** @x, align 8
31 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) nounwind
32 ; CHECK-NEXT:   ret void
33 ; CHECK-NEXT: }
34 define void @test1(i8* %p) {
35 entry:
36   %0 = tail call i8* @objc_retain(i8* %p) nounwind
37   %tmp = load volatile i8** @x, align 8
38   store i8* %0, i8** @x, align 8
39   tail call void @objc_release(i8* %tmp) nounwind
40   ret void
41 }
42
43 ; Don't do this if the store is volatile.
44
45 ;      CHECK: define void @test2(i8* %p) {
46 ; CHECK-NEXT: entry:
47 ; CHECK-NEXT:   %0 = tail call i8* @objc_retain(i8* %p) nounwind
48 ; CHECK-NEXT:   %tmp = load i8** @x, align 8
49 ; CHECK-NEXT:   store volatile i8* %0, i8** @x, align 8
50 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) nounwind
51 ; CHECK-NEXT:   ret void
52 ; CHECK-NEXT: }
53 define void @test2(i8* %p) {
54 entry:
55   %0 = tail call i8* @objc_retain(i8* %p) nounwind
56   %tmp = load i8** @x, align 8
57   store volatile i8* %0, i8** @x, align 8
58   tail call void @objc_release(i8* %tmp) nounwind
59   ret void
60 }
61
62 ; Don't do this if there's a use of the old pointer value between the store
63 ; and the release.
64
65 ; CHECK:      define void @test3(i8* %newValue) {
66 ; CHECK-NEXT: entry:
67 ; CHECK-NEXT:   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
68 ; CHECK-NEXT:   %x1 = load i8** @x, align 8
69 ; CHECK-NEXT:   store i8* %x0, i8** @x, align 8
70 ; CHECK-NEXT:   tail call void @use_pointer(i8* %x1), !clang.arc.no_objc_arc_exceptions !0
71 ; CHECK-NEXT:   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
72 ; CHECK-NEXT:   ret void
73 ; CHECK-NEXT: }
74 define void @test3(i8* %newValue) {
75 entry:
76   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
77   %x1 = load i8** @x, align 8
78   store i8* %newValue, i8** @x, align 8
79   tail call void @use_pointer(i8* %x1), !clang.arc.no_objc_arc_exceptions !0
80   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
81   ret void
82 }
83
84 ; Like test3, but with an icmp use instead of a call, for good measure.
85
86 ; CHECK:      define i1 @test4(i8* %newValue, i8* %foo) {
87 ; CHECK-NEXT: entry:
88 ; CHECK-NEXT:   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
89 ; CHECK-NEXT:   %x1 = load i8** @x, align 8
90 ; CHECK-NEXT:   store i8* %x0, i8** @x, align 8
91 ; CHECK-NEXT:   %t = icmp eq i8* %x1, %foo
92 ; CHECK-NEXT:   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
93 ; CHECK-NEXT:   ret i1 %t
94 ; CHECK-NEXT: }
95 define i1 @test4(i8* %newValue, i8* %foo) {
96 entry:
97   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
98   %x1 = load i8** @x, align 8
99   store i8* %newValue, i8** @x, align 8
100   %t = icmp eq i8* %x1, %foo
101   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
102   ret i1 %t
103 }
104
105 ; Do form an objc_storeStrong here, because the use is before the store.
106
107 ; CHECK: define i1 @test5(i8* %newValue, i8* %foo) {
108 ; CHECK: %t = icmp eq i8* %x1, %foo
109 ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) nounwind
110 define i1 @test5(i8* %newValue, i8* %foo) {
111 entry:
112   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
113   %x1 = load i8** @x, align 8
114   %t = icmp eq i8* %x1, %foo
115   store i8* %newValue, i8** @x, align 8
116   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
117   ret i1 %t
118 }
119
120 ; Like test5, but the release is before the store.
121
122 ; CHECK: define i1 @test6(i8* %newValue, i8* %foo) {
123 ; CHECK: %t = icmp eq i8* %x1, %foo
124 ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) nounwind
125 define i1 @test6(i8* %newValue, i8* %foo) {
126 entry:
127   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
128   %x1 = load i8** @x, align 8
129   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
130   %t = icmp eq i8* %x1, %foo
131   store i8* %newValue, i8** @x, align 8
132   ret i1 %t
133 }
134
135 ; Like test0, but there's no store, so don't form an objc_storeStrong.
136
137 ;      CHECK: define void @test7(
138 ; CHECK-NEXT: entry:
139 ; CHECK-NEXT:   %0 = tail call i8* @objc_retain(i8* %p) nounwind
140 ; CHECK-NEXT:   %tmp = load i8** @x, align 8
141 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) nounwind
142 ; CHECK-NEXT:   ret void
143 ; CHECK-NEXT: }
144 define void @test7(i8* %p) {
145 entry:
146   %0 = tail call i8* @objc_retain(i8* %p) nounwind
147   %tmp = load i8** @x, align 8
148   tail call void @objc_release(i8* %tmp) nounwind
149   ret void
150 }
151
152 ; Like test0, but there's no retain, so don't form an objc_storeStrong.
153
154 ;      CHECK: define void @test8(
155 ; CHECK-NEXT: entry:
156 ; CHECK-NEXT:   %tmp = load i8** @x, align 8
157 ; CHECK-NEXT:   store i8* %p, i8** @x, align 8
158 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) nounwind
159 ; CHECK-NEXT:   ret void
160 ; CHECK-NEXT: }
161 define void @test8(i8* %p) {
162 entry:
163   %tmp = load i8** @x, align 8
164   store i8* %p, i8** @x, align 8
165   tail call void @objc_release(i8* %tmp) nounwind
166   ret void
167 }
168
169 !0 = metadata !{}