John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 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*) |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 7 | declare void @use_pointer(i8*) |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 8 | |
| 9 | @x = external global i8* |
| 10 | |
Stephen Lin | a76289a | 2013-07-14 01:50:49 +0000 | [diff] [blame] | 11 | ; CHECK-LABEL: define void @test0( |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 12 | ; CHECK: entry: |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 13 | ; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) [[NUW:#[0-9]+]] |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 14 | ; CHECK-NEXT: ret void |
Michael Gottesman | b33b6cb | 2013-04-27 05:25:54 +0000 | [diff] [blame] | 15 | ; CHECK-NEXT: } |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 16 | define void @test0(i8* %p) { |
| 17 | entry: |
| 18 | %0 = tail call i8* @objc_retain(i8* %p) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 19 | %tmp = load i8*, i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 20 | store i8* %0, i8** @x, align 8 |
| 21 | tail call void @objc_release(i8* %tmp) nounwind |
| 22 | ret void |
| 23 | } |
| 24 | |
| 25 | ; Don't do this if the load is volatile. |
| 26 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 27 | ; CHECK-LABEL: define void @test1(i8* %p) { |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 28 | ; CHECK-NEXT: entry: |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 29 | ; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]] |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 30 | ; CHECK-NEXT: %tmp = load volatile i8*, i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 31 | ; CHECK-NEXT: store i8* %0, i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 32 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 33 | ; CHECK-NEXT: ret void |
| 34 | ; CHECK-NEXT: } |
| 35 | define void @test1(i8* %p) { |
| 36 | entry: |
| 37 | %0 = tail call i8* @objc_retain(i8* %p) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 38 | %tmp = load volatile i8*, i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 39 | store i8* %0, i8** @x, align 8 |
| 40 | tail call void @objc_release(i8* %tmp) nounwind |
| 41 | ret void |
| 42 | } |
| 43 | |
| 44 | ; Don't do this if the store is volatile. |
| 45 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 46 | ; CHECK-LABEL: define void @test2(i8* %p) { |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 47 | ; CHECK-NEXT: entry: |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 48 | ; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]] |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 49 | ; CHECK-NEXT: %tmp = load i8*, i8** @x, align 8 |
Eli Friedman | 02e737b | 2011-08-12 22:50:01 +0000 | [diff] [blame] | 50 | ; CHECK-NEXT: store volatile i8* %0, i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 51 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 52 | ; CHECK-NEXT: ret void |
| 53 | ; CHECK-NEXT: } |
| 54 | define void @test2(i8* %p) { |
| 55 | entry: |
| 56 | %0 = tail call i8* @objc_retain(i8* %p) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 57 | %tmp = load i8*, i8** @x, align 8 |
Chris Lattner | 6a144a2 | 2011-11-27 06:54:59 +0000 | [diff] [blame] | 58 | store volatile i8* %0, i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 59 | tail call void @objc_release(i8* %tmp) nounwind |
| 60 | ret void |
| 61 | } |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 62 | |
Filipe Cabecinhas | 5c43305 | 2012-05-09 14:43:50 +0000 | [diff] [blame] | 63 | ; Don't do this if there's a use of the old pointer value between the store |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 64 | ; and the release. |
| 65 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 66 | ; CHECK-LABEL: define void @test3(i8* %newValue) { |
| 67 | ; CHECK-NEXT: entry: |
| 68 | ; CHECK-NEXT: %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]] |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 69 | ; CHECK-NEXT: %x1 = load i8*, i8** @x, align 8 |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 70 | ; CHECK-NEXT: store i8* %x0, i8** @x, align 8 |
| 71 | ; CHECK-NEXT: tail call void @use_pointer(i8* %x1), !clang.arc.no_objc_arc_exceptions !0 |
| 72 | ; CHECK-NEXT: tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0 |
| 73 | ; CHECK-NEXT: ret void |
| 74 | ; CHECK-NEXT: } |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 75 | define void @test3(i8* %newValue) { |
| 76 | entry: |
| 77 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 78 | %x1 = load i8*, i8** @x, align 8 |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 79 | store i8* %newValue, i8** @x, align 8 |
| 80 | tail call void @use_pointer(i8* %x1), !clang.arc.no_objc_arc_exceptions !0 |
| 81 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 82 | ret void |
| 83 | } |
| 84 | |
| 85 | ; Like test3, but with an icmp use instead of a call, for good measure. |
| 86 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 87 | ; CHECK-LABEL: define i1 @test4(i8* %newValue, i8* %foo) { |
| 88 | ; CHECK-NEXT: entry: |
| 89 | ; CHECK-NEXT: %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]] |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 90 | ; CHECK-NEXT: %x1 = load i8*, i8** @x, align 8 |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 91 | ; CHECK-NEXT: store i8* %x0, i8** @x, align 8 |
| 92 | ; CHECK-NEXT: %t = icmp eq i8* %x1, %foo |
| 93 | ; CHECK-NEXT: tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0 |
| 94 | ; CHECK-NEXT: ret i1 %t |
| 95 | ; CHECK-NEXT: } |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 96 | define i1 @test4(i8* %newValue, i8* %foo) { |
| 97 | entry: |
| 98 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 99 | %x1 = load i8*, i8** @x, align 8 |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 100 | store i8* %newValue, i8** @x, align 8 |
| 101 | %t = icmp eq i8* %x1, %foo |
| 102 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 103 | ret i1 %t |
| 104 | } |
| 105 | |
| 106 | ; Do form an objc_storeStrong here, because the use is before the store. |
| 107 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 108 | ; CHECK-LABEL: define i1 @test5(i8* %newValue, i8* %foo) { |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 109 | ; CHECK: %t = icmp eq i8* %x1, %foo |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 110 | ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]] |
Michael Gottesman | b33b6cb | 2013-04-27 05:25:54 +0000 | [diff] [blame] | 111 | ; CHECK: } |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 112 | define i1 @test5(i8* %newValue, i8* %foo) { |
| 113 | entry: |
| 114 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 115 | %x1 = load i8*, i8** @x, align 8 |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 116 | %t = icmp eq i8* %x1, %foo |
| 117 | store i8* %newValue, i8** @x, align 8 |
| 118 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 119 | ret i1 %t |
| 120 | } |
| 121 | |
| 122 | ; Like test5, but the release is before the store. |
| 123 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 124 | ; CHECK-LABEL: define i1 @test6(i8* %newValue, i8* %foo) { |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 125 | ; CHECK: %t = icmp eq i8* %x1, %foo |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 126 | ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]] |
Michael Gottesman | b33b6cb | 2013-04-27 05:25:54 +0000 | [diff] [blame] | 127 | ; CHECK: } |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 128 | define i1 @test6(i8* %newValue, i8* %foo) { |
| 129 | entry: |
| 130 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 131 | %x1 = load i8*, i8** @x, align 8 |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 132 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 133 | %t = icmp eq i8* %x1, %foo |
| 134 | store i8* %newValue, i8** @x, align 8 |
| 135 | ret i1 %t |
| 136 | } |
| 137 | |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 138 | ; Like test0, but there's no store, so don't form an objc_storeStrong. |
| 139 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 140 | ; CHECK-LABEL: define void @test7( |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 141 | ; CHECK-NEXT: entry: |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 142 | ; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]] |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 143 | ; CHECK-NEXT: %tmp = load i8*, i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 144 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 145 | ; CHECK-NEXT: ret void |
| 146 | ; CHECK-NEXT: } |
| 147 | define void @test7(i8* %p) { |
| 148 | entry: |
| 149 | %0 = tail call i8* @objc_retain(i8* %p) nounwind |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 150 | %tmp = load i8*, i8** @x, align 8 |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 151 | tail call void @objc_release(i8* %tmp) nounwind |
| 152 | ret void |
| 153 | } |
| 154 | |
| 155 | ; Like test0, but there's no retain, so don't form an objc_storeStrong. |
| 156 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 157 | ; CHECK-LABEL: define void @test8( |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 158 | ; CHECK-NEXT: entry: |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 159 | ; CHECK-NEXT: %tmp = load i8*, i8** @x, align 8 |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 160 | ; CHECK-NEXT: store i8* %p, i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 161 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 162 | ; CHECK-NEXT: ret void |
| 163 | ; CHECK-NEXT: } |
| 164 | define void @test8(i8* %p) { |
| 165 | entry: |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 166 | %tmp = load i8*, i8** @x, align 8 |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 167 | store i8* %p, i8** @x, align 8 |
| 168 | tail call void @objc_release(i8* %tmp) nounwind |
| 169 | ret void |
| 170 | } |
| 171 | |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 172 | ; Make sure that we properly handle release that *may* release our new |
| 173 | ; value in between the retain and the store. We need to be sure that |
| 174 | ; this we can safely move the retain to the store. This specific test |
| 175 | ; makes sure that we properly handled a release of an unrelated |
| 176 | ; pointer. |
| 177 | ; |
| 178 | ; CHECK-LABEL: define i1 @test9(i8* %newValue, i8* %foo, i8* %unrelated_ptr) { |
| 179 | ; CHECK-NOT: objc_storeStrong |
| 180 | define i1 @test9(i8* %newValue, i8* %foo, i8* %unrelated_ptr) { |
| 181 | entry: |
| 182 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
| 183 | tail call void @objc_release(i8* %unrelated_ptr) nounwind, !clang.imprecise_release !0 |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 184 | %x1 = load i8*, i8** @x, align 8 |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 185 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 186 | %t = icmp eq i8* %x1, %foo |
| 187 | store i8* %newValue, i8** @x, align 8 |
| 188 | ret i1 %t |
| 189 | } |
| 190 | |
| 191 | ; Make sure that we don't perform the optimization when we just have a call. |
| 192 | ; |
| 193 | ; CHECK-LABEL: define i1 @test10(i8* %newValue, i8* %foo, i8* %unrelated_ptr) { |
| 194 | ; CHECK-NOT: objc_storeStrong |
| 195 | define i1 @test10(i8* %newValue, i8* %foo, i8* %unrelated_ptr) { |
| 196 | entry: |
| 197 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
| 198 | call void @use_pointer(i8* %unrelated_ptr) |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 199 | %x1 = load i8*, i8** @x, align 8 |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 200 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 201 | %t = icmp eq i8* %x1, %foo |
| 202 | store i8* %newValue, i8** @x, align 8 |
| 203 | ret i1 %t |
| 204 | } |
| 205 | |
| 206 | ; Make sure we form the store strong if the use in between the retain |
| 207 | ; and the store does not touch reference counts. |
| 208 | ; CHECK-LABEL: define i1 @test11(i8* %newValue, i8* %foo, i8* %unrelated_ptr) { |
| 209 | ; CHECK: objc_storeStrong |
| 210 | define i1 @test11(i8* %newValue, i8* %foo, i8* %unrelated_ptr) { |
| 211 | entry: |
| 212 | %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind |
| 213 | %t = icmp eq i8* %newValue, %foo |
David Blaikie | a79ac14 | 2015-02-27 21:17:42 +0000 | [diff] [blame] | 214 | %x1 = load i8*, i8** @x, align 8 |
Michael Gottesman | 0fc2acc | 2015-02-20 00:02:49 +0000 | [diff] [blame] | 215 | tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0 |
| 216 | store i8* %newValue, i8** @x, align 8 |
| 217 | ret i1 %t |
| 218 | } |
| 219 | |
Pete Cooper | 1929b55 | 2016-05-27 02:13:53 +0000 | [diff] [blame] | 220 | ; Make sure that we form the store strong even if there are bitcasts on |
| 221 | ; the pointers. |
| 222 | ; CHECK-LABEL: define void @test12( |
| 223 | ; CHECK: entry: |
| 224 | ; CHECK-NEXT: %p16 = bitcast i8** @x to i16** |
| 225 | ; CHECK-NEXT: %tmp16 = load i16*, i16** %p16, align 8 |
| 226 | ; CHECK-NEXT: %tmp8 = bitcast i16* %tmp16 to i8* |
| 227 | ; CHECK-NEXT: %p32 = bitcast i8** @x to i32** |
| 228 | ; CHECK-NEXT: %v32 = bitcast i8* %p to i32* |
| 229 | ; CHECK-NEXT: %0 = bitcast i16** %p16 to i8** |
| 230 | ; CHECK-NEXT: tail call void @objc_storeStrong(i8** %0, i8* %p) |
| 231 | ; CHECK-NEXT: ret void |
| 232 | ; CHECK-NEXT: } |
| 233 | define void @test12(i8* %p) { |
| 234 | entry: |
| 235 | %retain = tail call i8* @objc_retain(i8* %p) nounwind |
| 236 | %p16 = bitcast i8** @x to i16** |
| 237 | %tmp16 = load i16*, i16** %p16, align 8 |
| 238 | %tmp8 = bitcast i16* %tmp16 to i8* |
| 239 | %p32 = bitcast i8** @x to i32** |
| 240 | %v32 = bitcast i8* %retain to i32* |
| 241 | store i32* %v32, i32** %p32, align 8 |
| 242 | tail call void @objc_release(i8* %tmp8) nounwind |
| 243 | ret void |
| 244 | } |
| 245 | |
Akira Hatanaka | 75be84f | 2017-04-05 03:44:09 +0000 | [diff] [blame^] | 246 | ; This used to crash. |
| 247 | ; CHECK-LABEL: define i8* @test13( |
| 248 | ; CHECK: tail call void @objc_storeStrong(i8** %{{.*}}, i8* %[[NEW:.*]]) |
| 249 | ; CHECK-NEXT: ret i8* %[[NEW]] |
| 250 | |
| 251 | define i8* @test13(i8* %a0, i8* %a1, i8** %addr, i8* %new) { |
| 252 | %old = load i8*, i8** %addr, align 8 |
| 253 | call void @objc_release(i8* %old) |
| 254 | %retained = call i8* @objc_retain(i8* %new) |
| 255 | store i8* %retained, i8** %addr, align 8 |
| 256 | ret i8* %retained |
| 257 | } |
| 258 | |
Duncan P. N. Exon Smith | be7ea19 | 2014-12-15 19:07:53 +0000 | [diff] [blame] | 259 | !0 = !{} |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame] | 260 | |
| 261 | ; CHECK: attributes [[NUW]] = { nounwind } |