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 | |
| 11 | ; CHECK: define void @test0( |
| 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 |
| 15 | define void @test0(i8* %p) { |
| 16 | entry: |
| 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 28 | ; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]] |
Eli Friedman | 02e737b | 2011-08-12 22:50:01 +0000 | [diff] [blame] | 29 | ; CHECK-NEXT: %tmp = load volatile i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 30 | ; CHECK-NEXT: store i8* %0, i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 31 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 32 | ; CHECK-NEXT: ret void |
| 33 | ; CHECK-NEXT: } |
| 34 | define void @test1(i8* %p) { |
| 35 | entry: |
| 36 | %0 = tail call i8* @objc_retain(i8* %p) nounwind |
Chris Lattner | 6a144a2 | 2011-11-27 06:54:59 +0000 | [diff] [blame] | 37 | %tmp = load volatile i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 38 | 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 47 | ; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]] |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 48 | ; CHECK-NEXT: %tmp = load i8** @x, align 8 |
Eli Friedman | 02e737b | 2011-08-12 22:50:01 +0000 | [diff] [blame] | 49 | ; CHECK-NEXT: store volatile i8* %0, i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 50 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 51 | ; CHECK-NEXT: ret void |
| 52 | ; CHECK-NEXT: } |
| 53 | define void @test2(i8* %p) { |
| 54 | entry: |
| 55 | %0 = tail call i8* @objc_retain(i8* %p) nounwind |
| 56 | %tmp = load i8** @x, align 8 |
Chris Lattner | 6a144a2 | 2011-11-27 06:54:59 +0000 | [diff] [blame] | 57 | store volatile i8* %0, i8** @x, align 8 |
John McCall | d935e9c | 2011-06-15 23:37:01 +0000 | [diff] [blame] | 58 | tail call void @objc_release(i8* %tmp) nounwind |
| 59 | ret void |
| 60 | } |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 61 | |
Filipe Cabecinhas | 5c43305 | 2012-05-09 14:43:50 +0000 | [diff] [blame] | 62 | ; 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] | 63 | ; and the release. |
| 64 | |
| 65 | ; CHECK: define void @test3(i8* %newValue) { |
| 66 | ; CHECK-NEXT: entry: |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 67 | ; CHECK-NEXT: %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]] |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 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 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 71 | ; CHECK-NEXT: tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0 |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 72 | ; CHECK-NEXT: ret void |
| 73 | ; CHECK-NEXT: } |
| 74 | define void @test3(i8* %newValue) { |
| 75 | entry: |
| 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 88 | ; CHECK-NEXT: %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]] |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 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 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 92 | ; CHECK-NEXT: tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0 |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 93 | ; CHECK-NEXT: ret i1 %t |
| 94 | ; CHECK-NEXT: } |
| 95 | define i1 @test4(i8* %newValue, i8* %foo) { |
| 96 | entry: |
| 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 109 | ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]] |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 110 | define i1 @test5(i8* %newValue, i8* %foo) { |
| 111 | entry: |
| 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 124 | ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]] |
Dan Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 125 | define i1 @test6(i8* %newValue, i8* %foo) { |
| 126 | entry: |
| 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 Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 135 | ; 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 139 | ; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %p) [[NUW]] |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 140 | ; CHECK-NEXT: %tmp = load i8** @x, align 8 |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 141 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 142 | ; CHECK-NEXT: ret void |
| 143 | ; CHECK-NEXT: } |
| 144 | define void @test7(i8* %p) { |
| 145 | entry: |
| 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 Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 158 | ; CHECK-NEXT: tail call void @objc_release(i8* %tmp) [[NUW]] |
Dan Gohman | f8b19d0 | 2012-05-09 23:08:33 +0000 | [diff] [blame] | 159 | ; CHECK-NEXT: ret void |
| 160 | ; CHECK-NEXT: } |
| 161 | define void @test8(i8* %p) { |
| 162 | entry: |
| 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 Gohman | 61708d3 | 2012-05-08 23:34:08 +0000 | [diff] [blame] | 169 | !0 = metadata !{} |
Bill Wendling | a032374 | 2013-02-22 09:09:42 +0000 | [diff] [blame^] | 170 | |
| 171 | ; CHECK: attributes [[NUW]] = { nounwind } |