1 ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
3 target datalayout = "e-p:64:64:64"
5 declare i8* @objc_retain(i8*)
6 declare void @objc_release(i8*)
7 declare void @use_pointer(i8*)
9 @x = external global i8*
11 ; CHECK: define void @test0(
13 ; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) nounwind
14 ; CHECK-NEXT: ret void
15 define void @test0(i8* %p) {
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
24 ; Don't do this if the load is volatile.
26 ; CHECK: define void @test1(i8* %p) {
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
34 define void @test1(i8* %p) {
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
43 ; Don't do this if the store is volatile.
45 ; CHECK: define void @test2(i8* %p) {
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
53 define void @test2(i8* %p) {
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
62 ; Don't do this if there's a use of the old pointer value between the store
65 ; CHECK: define void @test3(i8* %newValue) {
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
74 define void @test3(i8* %newValue) {
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
84 ; Like test3, but with an icmp use instead of a call, for good measure.
86 ; CHECK: define i1 @test4(i8* %newValue, i8* %foo) {
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
95 define i1 @test4(i8* %newValue, i8* %foo) {
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
105 ; Do form an objc_storeStrong here, because the use is before the store.
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) {
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
120 ; Like test5, but the release is before the store.
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) {
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