blob: 376120cf8bf9b95e7ea07917dbb5cdf9a981c625 [file] [log] [blame]
John McCalld935e9c2011-06-15 23:37:01 +00001; 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*)
Dan Gohman61708d32012-05-08 23:34:08 +00007declare void @use_pointer(i8*)
John McCalld935e9c2011-06-15 23:37:01 +00008
9@x = external global i8*
10
11; CHECK: define void @test0(
12; CHECK: entry:
Dan Gohman8ee108b2012-01-19 19:14:36 +000013; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) nounwind
John McCalld935e9c2011-06-15 23:37:01 +000014; CHECK-NEXT: ret void
15define void @test0(i8* %p) {
16entry:
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
Eli Friedman02e737b2011-08-12 22:50:01 +000029; CHECK-NEXT: %tmp = load volatile i8** @x, align 8
John McCalld935e9c2011-06-15 23:37:01 +000030; 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: }
34define void @test1(i8* %p) {
35entry:
36 %0 = tail call i8* @objc_retain(i8* %p) nounwind
Chris Lattner6a144a22011-11-27 06:54:59 +000037 %tmp = load volatile i8** @x, align 8
John McCalld935e9c2011-06-15 23:37:01 +000038 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
Eli Friedman02e737b2011-08-12 22:50:01 +000049; CHECK-NEXT: store volatile i8* %0, i8** @x, align 8
John McCalld935e9c2011-06-15 23:37:01 +000050; CHECK-NEXT: tail call void @objc_release(i8* %tmp) nounwind
51; CHECK-NEXT: ret void
52; CHECK-NEXT: }
53define void @test2(i8* %p) {
54entry:
55 %0 = tail call i8* @objc_retain(i8* %p) nounwind
56 %tmp = load i8** @x, align 8
Chris Lattner6a144a22011-11-27 06:54:59 +000057 store volatile i8* %0, i8** @x, align 8
John McCalld935e9c2011-06-15 23:37:01 +000058 tail call void @objc_release(i8* %tmp) nounwind
59 ret void
60}
Dan Gohman61708d32012-05-08 23:34:08 +000061
62; Don't do this if there's a use of the old pointer vlaue 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: }
74define void @test3(i8* %newValue) {
75entry:
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: }
95define i1 @test4(i8* %newValue, i8* %foo) {
96entry:
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
110define i1 @test5(i8* %newValue, i8* %foo) {
111entry:
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
125define i1 @test6(i8* %newValue, i8* %foo) {
126entry:
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!0 = metadata !{}