blob: 6999237300e762045a834cce7ab8fb734815e4d1 [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:
Bill Wendlinga0323742013-02-22 09:09:42 +000013; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) [[NUW:#[0-9]+]]
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:
Bill Wendlinga0323742013-02-22 09:09:42 +000028; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]]
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
Bill Wendlinga0323742013-02-22 09:09:42 +000031; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]]
John McCalld935e9c2011-06-15 23:37:01 +000032; 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:
Bill Wendlinga0323742013-02-22 09:09:42 +000047; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]]
John McCalld935e9c2011-06-15 23:37:01 +000048; 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
Bill Wendlinga0323742013-02-22 09:09:42 +000050; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]]
John McCalld935e9c2011-06-15 23:37:01 +000051; 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
Filipe Cabecinhas5c433052012-05-09 14:43:50 +000062; Don't do this if there's a use of the old pointer value between the store
Dan Gohman61708d32012-05-08 23:34:08 +000063; and the release.
64
65; CHECK: define void @test3(i8* %newValue) {
66; CHECK-NEXT: entry:
Bill Wendlinga0323742013-02-22 09:09:42 +000067; CHECK-NEXT: %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]]
Dan Gohman61708d32012-05-08 23:34:08 +000068; 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
Bill Wendlinga0323742013-02-22 09:09:42 +000071; CHECK-NEXT: tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0
Dan Gohman61708d32012-05-08 23:34:08 +000072; 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:
Bill Wendlinga0323742013-02-22 09:09:42 +000088; CHECK-NEXT: %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]]
Dan Gohman61708d32012-05-08 23:34:08 +000089; 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
Bill Wendlinga0323742013-02-22 09:09:42 +000092; CHECK-NEXT: tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0
Dan Gohman61708d32012-05-08 23:34:08 +000093; 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
Bill Wendlinga0323742013-02-22 09:09:42 +0000109; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]]
Dan Gohman61708d32012-05-08 23:34:08 +0000110define 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
Bill Wendlinga0323742013-02-22 09:09:42 +0000124; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]]
Dan Gohman61708d32012-05-08 23:34:08 +0000125define 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
Dan Gohmanf8b19d02012-05-09 23:08:33 +0000135; Like test0, but there's no store, so don't form an objc_storeStrong.
136
137; CHECK: define void @test7(
138; CHECK-NEXT: entry:
Bill Wendlinga0323742013-02-22 09:09:42 +0000139; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]]
Dan Gohmanf8b19d02012-05-09 23:08:33 +0000140; CHECK-NEXT: %tmp = load i8** @x, align 8
Bill Wendlinga0323742013-02-22 09:09:42 +0000141; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]]
Dan Gohmanf8b19d02012-05-09 23:08:33 +0000142; CHECK-NEXT: ret void
143; CHECK-NEXT: }
144define void @test7(i8* %p) {
145entry:
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
Bill Wendlinga0323742013-02-22 09:09:42 +0000158; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]]
Dan Gohmanf8b19d02012-05-09 23:08:33 +0000159; CHECK-NEXT: ret void
160; CHECK-NEXT: }
161define void @test8(i8* %p) {
162entry:
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
Dan Gohman61708d32012-05-08 23:34:08 +0000169!0 = metadata !{}
Bill Wendlinga0323742013-02-22 09:09:42 +0000170
171; CHECK: attributes [[NUW]] = { nounwind }