Home | History | Annotate | Download | only in ObjCARC
      1 ; RUN: opt -objc-arc -S < %s | FileCheck %s
      2 
      3 target datalayout = "e-p:64:64:64"
      4 
      5 declare i8* @objc_retain(i8*)
      6 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
      7 declare void @objc_release(i8*)
      8 declare i8* @objc_autorelease(i8*)
      9 declare i8* @objc_autoreleaseReturnValue(i8*)
     10 declare i8* @objc_retainAutoreleaseReturnValue(i8*)
     11 declare void @objc_autoreleasePoolPop(i8*)
     12 declare void @objc_autoreleasePoolPush()
     13 declare i8* @objc_retainBlock(i8*)
     14 
     15 declare i8* @objc_retainedObject(i8*)
     16 declare i8* @objc_unretainedObject(i8*)
     17 declare i8* @objc_unretainedPointer(i8*)
     18 
     19 declare void @use_pointer(i8*)
     20 declare void @callee()
     21 declare void @callee_fnptr(void ()*)
     22 declare void @invokee()
     23 declare i8* @returner()
     24 
     25 ; Test that retain+release elimination is suppressed when the
     26 ; retain is an objc_retainAutoreleasedReturnValue, since it's
     27 ; better to do the RV optimization.
     28 
     29 ; CHECK:      define void @test0(
     30 ; CHECK-NEXT: entry:
     31 ; CHECK-NEXT:   %x = call i8* @returner
     32 ; CHECK-NEXT:   %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %x) nounwind
     33 ; CHECK: t:
     34 ; CHECK-NOT: @objc_
     35 ; CHECK: return:
     36 ; CHECK-NEXT: call void @objc_release(i8* %x)
     37 ; CHECK-NEXT: ret void
     38 ; CHECK-NEXT: }
     39 define void @test0(i1 %p) nounwind {
     40 entry:
     41   %x = call i8* @returner()
     42   %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %x)
     43   br i1 %p, label %t, label %return
     44 
     45 t:
     46   call void @use_pointer(i8* %x)
     47   store i8 0, i8* %x
     48   br label %return
     49 
     50 return:
     51   call void @objc_release(i8* %x) nounwind
     52   ret void
     53 }
     54 
     55 ; Delete no-ops.
     56 
     57 ; CHECK: define void @test2
     58 ; CHECK-NOT: @objc_
     59 ; CHECK: }
     60 define void @test2() {
     61   call i8* @objc_retainAutoreleasedReturnValue(i8* null)
     62   call i8* @objc_autoreleaseReturnValue(i8* null)
     63   ; call i8* @objc_retainAutoreleaseReturnValue(i8* null) ; TODO
     64   ret void
     65 }
     66 
     67 ; Delete a redundant retainRV,autoreleaseRV when forwaring a call result
     68 ; directly to a return value.
     69 
     70 ; CHECK: define i8* @test3
     71 ; CHECK: call i8* @returner()
     72 ; CHECK-NEXT: ret i8* %call
     73 define i8* @test3() {
     74 entry:
     75   %call = call i8* @returner()
     76   %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
     77   %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
     78   ret i8* %1
     79 }
     80 
     81 ; Delete a redundant retain,autoreleaseRV when forwaring a call result
     82 ; directly to a return value.
     83 
     84 ; CHECK: define i8* @test4
     85 ; CHECK: call i8* @returner()
     86 ; CHECK-NEXT: ret i8* %call
     87 define i8* @test4() {
     88 entry:
     89   %call = call i8* @returner()
     90   %0 = call i8* @objc_retain(i8* %call) nounwind
     91   %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
     92   ret i8* %1
     93 }
     94 
     95 ; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
     96 ; directly to a return value.
     97 
     98 ; TODO
     99 ; HECK: define i8* @test5
    100 ; HECK: call i8* @returner()
    101 ; HECK-NEXT: ret i8* %call
    102 ;define i8* @test5() {
    103 ;entry:
    104 ;  %call = call i8* @returner()
    105 ;  %0 = call i8* @objc_retainAutoreleaseReturnValue(i8* %call) nounwind
    106 ;  ret i8* %0
    107 ;}
    108 
    109 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
    110 ; an objc_autorelease.
    111 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
    112 ; objc_retainAutoreleasedReturnValueAutorelease and merge
    113 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
    114 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
    115 ; Those entrypoints don't exist yet though.
    116 
    117 ; CHECK: define i8* @test7(
    118 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    119 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    120 define i8* @test7() {
    121   %p = call i8* @returner()
    122   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    123   %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
    124   call void @use_pointer(i8* %t)
    125   ret i8* %t
    126 }
    127 
    128 ; CHECK: define i8* @test7b(
    129 ; CHECK: call i8* @objc_retain(i8* %p)
    130 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    131 define i8* @test7b() {
    132   %p = call i8* @returner()
    133   call void @use_pointer(i8* %p)
    134   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    135   %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
    136   ret i8* %t
    137 }
    138 
    139 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
    140 ; is a return value.
    141 
    142 ; CHECK: define void @test8()
    143 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    144 define void @test8() {
    145   %p = call i8* @returner()
    146   call i8* @objc_retain(i8* %p)
    147   ret void
    148 }
    149 
    150 ; Don't apply the RV optimization to autorelease if there's no retain.
    151 
    152 ; CHECK: define i8* @test9(i8* %p)
    153 ; CHECK: tail call i8* @objc_autorelease(i8* %p)
    154 define i8* @test9(i8* %p) {
    155   call i8* @objc_autorelease(i8* %p)
    156   ret i8* %p
    157 }
    158 
    159 ; Apply the RV optimization.
    160 
    161 ; CHECK: define i8* @test10(i8* %p)
    162 ; CHECK: tail call i8* @objc_retain(i8* %p) nounwind
    163 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
    164 ; CHECK-NEXT: ret i8* %p
    165 define i8* @test10(i8* %p) {
    166   %1 = call i8* @objc_retain(i8* %p)
    167   %2 = call i8* @objc_autorelease(i8* %p)
    168   ret i8* %p
    169 }
    170 
    171 ; Don't do the autoreleaseRV optimization because @use_pointer
    172 ; could undo the retain.
    173 
    174 ; CHECK: define i8* @test11(i8* %p)
    175 ; CHECK: tail call i8* @objc_retain(i8* %p)
    176 ; CHECK-NEXT: call void @use_pointer(i8* %p)
    177 ; CHECK: tail call i8* @objc_autorelease(i8* %p)
    178 ; CHECK-NEXT: ret i8* %p
    179 define i8* @test11(i8* %p) {
    180   %1 = call i8* @objc_retain(i8* %p)
    181   call void @use_pointer(i8* %p)
    182   %2 = call i8* @objc_autorelease(i8* %p)
    183   ret i8* %p
    184 }
    185 
    186 ; Don't spoil the RV optimization.
    187 
    188 ; CHECK: define i8* @test12(i8* %p)
    189 ; CHECK: tail call i8* @objc_retain(i8* %p)
    190 ; CHECK: call void @use_pointer(i8* %p)
    191 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    192 ; CHECK: ret i8* %p
    193 define i8* @test12(i8* %p) {
    194   %1 = call i8* @objc_retain(i8* %p)
    195   call void @use_pointer(i8* %p)
    196   %2 = call i8* @objc_autoreleaseReturnValue(i8* %p)
    197   ret i8* %p
    198 }
    199 
    200 ; Don't zap the objc_retainAutoreleasedReturnValue.
    201 
    202 ; CHECK: define i8* @test13(
    203 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    204 ; CHECK: tail call i8* @objc_autorelease(i8* %p)
    205 ; CHECK: ret i8* %p
    206 define i8* @test13() {
    207   %p = call i8* @returner()
    208   %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    209   call void @callee()
    210   %2 = call i8* @objc_autorelease(i8* %p)
    211   ret i8* %p
    212 }
    213 
    214 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
    215 ; argument is not a return value.
    216 
    217 ; CHECK: define void @test14(
    218 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) nounwind
    219 ; CHECK-NEXT: ret void
    220 define void @test14(i8* %p) {
    221   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    222   ret void
    223 }
    224 
    225 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
    226 ; argument is a return value.
    227 
    228 ; CHECK: define void @test15(
    229 ; CHECK-NEXT: %y = call i8* @returner()
    230 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind
    231 ; CHECK-NEXT: ret void
    232 define void @test15() {
    233   %y = call i8* @returner()
    234   call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
    235   ret void
    236 }
    237 
    238 ; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
    239 ; argument is a return value.
    240 
    241 ; CHECK: define void @test16(
    242 ; CHECK-NEXT: %y = call i8* @returner()
    243 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind
    244 ; CHECK-NEXT: ret void
    245 define void @test16() {
    246   %y = call i8* @returner()
    247   call i8* @objc_retain(i8* %y)
    248   ret void
    249 }
    250 
    251 ; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
    252 ; argument is not a return value.
    253 
    254 ; CHECK: define void @test17(
    255 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
    256 ; CHECK-NEXT: ret void
    257 define void @test17(i8* %y) {
    258   call i8* @objc_retain(i8* %y)
    259   ret void
    260 }
    261 
    262 ; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
    263 ; isn't next to the call providing its return value.
    264 
    265 ; CHECK: define void @test18(
    266 ; CHECK-NEXT: %y = call i8* @returner()
    267 ; CHECK-NEXT: call void @callee()
    268 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
    269 ; CHECK-NEXT: ret void
    270 define void @test18() {
    271   %y = call i8* @returner()
    272   call void @callee()
    273   call i8* @objc_retain(i8* %y)
    274   ret void
    275 }
    276 
    277 ; Delete autoreleaseRV+retainRV pairs.
    278 
    279 ; CHECK: define i8* @test19(i8* %p) {
    280 ; CHECK-NEXT: ret i8* %p
    281 define i8* @test19(i8* %p) {
    282   call i8* @objc_autoreleaseReturnValue(i8* %p)
    283   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    284   ret i8* %p
    285 }
    286 
    287 ; Like test19 but with plain autorelease.
    288 
    289 ; CHECK: define i8* @test20(i8* %p) {
    290 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
    291 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
    292 ; CHECK-NEXT: ret i8* %p
    293 define i8* @test20(i8* %p) {
    294   call i8* @objc_autorelease(i8* %p)
    295   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    296   ret i8* %p
    297 }
    298 
    299 ; Like test19 but with plain retain.
    300 
    301 ; CHECK: define i8* @test21(i8* %p) {
    302 ; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p)
    303 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
    304 ; CHECK-NEXT: ret i8* %p
    305 define i8* @test21(i8* %p) {
    306   call i8* @objc_autoreleaseReturnValue(i8* %p)
    307   call i8* @objc_retain(i8* %p)
    308   ret i8* %p
    309 }
    310 
    311 ; Like test19 but with plain retain and autorelease.
    312 
    313 ; CHECK: define i8* @test22(i8* %p) {
    314 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
    315 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
    316 ; CHECK-NEXT: ret i8* %p
    317 define i8* @test22(i8* %p) {
    318   call i8* @objc_autorelease(i8* %p)
    319   call i8* @objc_retain(i8* %p)
    320   ret i8* %p
    321 }
    322 
    323 ; Convert autoreleaseRV to autorelease.
    324 
    325 ; CHECK: define void @test23(
    326 ; CHECK: tail call i8* @objc_autorelease(i8* %p) nounwind
    327 define void @test23(i8* %p) {
    328   store i8 0, i8* %p
    329   call i8* @objc_autoreleaseReturnValue(i8* %p)
    330   ret void
    331 }
    332