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 i8* @objc_autorelease(i8*)
8 declare i8* @objc_autoreleaseReturnValue(i8*)
9 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
11 declare void @use_pointer(i8*)
12 declare i8* @returner()
14 ; CHECK: define void @test0
15 ; CHECK: call void @use_pointer(i8* %0)
17 define void @test0(i8* %x) nounwind {
19 %0 = call i8* @objc_retain(i8* %x) nounwind
20 call void @use_pointer(i8* %x)
24 ; CHECK: define void @test1
25 ; CHECK: call void @use_pointer(i8* %0)
27 define void @test1(i8* %x) nounwind {
29 %0 = call i8* @objc_autorelease(i8* %x) nounwind
30 call void @use_pointer(i8* %x)
34 ; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
36 ; CHECK: define void @test2(
37 ; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW:#[0-9]+]]
39 define void @test2(i8* %x) nounwind {
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)
47 ; Same as test2 but the value is returned. Do an RV optimization.
49 ; CHECK: define i8* @test2b(
50 ; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) [[NUW]]
52 define i8* @test2b(i8* %x) nounwind {
54 %0 = tail call i8* @objc_retain(i8* %x) nounwind
55 tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
59 ; Merge a retain,autorelease pair around a call.
61 ; CHECK: define void @test3(
62 ; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW]]
63 ; CHECK: @use_pointer(i8* %0)
65 define void @test3(i8* %x, i64 %n) {
67 tail call i8* @objc_retain(i8* %x) nounwind
68 call void @use_pointer(i8* %x)
69 call i8* @objc_autorelease(i8* %x) nounwind
73 ; Trivial retain,autorelease pair with intervening call, but it's post-dominated
74 ; by another release. The retain and autorelease can be merged.
76 ; CHECK: define void @test4(
78 ; CHECK-NEXT: @objc_retainAutorelease(i8* %x) [[NUW]]
79 ; CHECK-NEXT: @use_pointer
80 ; CHECK-NEXT: @objc_release
81 ; CHECK-NEXT: ret void
83 define void @test4(i8* %x, i64 %n) {
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
92 ; Don't merge retain and autorelease if they're not control-equivalent.
94 ; CHECK: define void @test5(
95 ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
97 ; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]]
99 define void @test5(i8* %p, i1 %a) {
101 tail call i8* @objc_retain(i8* %p) nounwind
102 br i1 %a, label %true, label %false
105 call i8* @objc_autorelease(i8* %p) nounwind
106 call void @use_pointer(i8* %p)
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.
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]]
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)
133 ; Don't spoil the RV optimization.
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)
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)
147 ; Do the return value substitution for PHI nodes too.
149 ; CHECK: define i8* @test8(
150 ; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ]
152 define i8* @test8(i1 %x, i8* %c) {
154 br i1 %x, label %return, label %if.then
156 if.then: ; preds = %entry
157 %p = call i8* @objc_retain(i8* %c) nounwind
160 return: ; preds = %if.then, %entry
161 %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
165 ; Kill calls to @clang.arc.use(...)
166 ; CHECK: define void @test9(
167 ; CHECK-NOT: clang.arc.use
169 define void @test9(i8* %a, i8* %b) {
170 call void (...)* @clang.arc.use(i8* %a, i8* %b) nounwind
174 declare void @clang.arc.use(...) nounwind
176 ; CHECK: attributes [[NUW]] = { nounwind }