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-LABEL:      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) [[NUW:#[0-9]+]]
     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-LABEL: 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-LABEL: 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-LABEL: 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-LABEL: 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* %p)
    125   ret i8* %t
    126 }
    127 
    128 ; CHECK-LABEL: 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* %p
    137 }
    138 
    139 ; Don't apply the RV optimization to autorelease if there's no retain.
    140 
    141 ; CHECK: define i8* @test9(i8* %p)
    142 ; CHECK: call i8* @objc_autorelease(i8* %p)
    143 define i8* @test9(i8* %p) {
    144   call i8* @objc_autorelease(i8* %p)
    145   ret i8* %p
    146 }
    147 
    148 ; Do not apply the RV optimization.
    149 
    150 ; CHECK: define i8* @test10(i8* %p)
    151 ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
    152 ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]]
    153 ; CHECK-NEXT: ret i8* %p
    154 define i8* @test10(i8* %p) {
    155   %1 = call i8* @objc_retain(i8* %p)
    156   %2 = call i8* @objc_autorelease(i8* %p)
    157   ret i8* %p
    158 }
    159 
    160 ; Don't do the autoreleaseRV optimization because @use_pointer
    161 ; could undo the retain.
    162 
    163 ; CHECK: define i8* @test11(i8* %p)
    164 ; CHECK: tail call i8* @objc_retain(i8* %p)
    165 ; CHECK-NEXT: call void @use_pointer(i8* %p)
    166 ; CHECK: call i8* @objc_autorelease(i8* %p)
    167 ; CHECK-NEXT: ret i8* %p
    168 define i8* @test11(i8* %p) {
    169   %1 = call i8* @objc_retain(i8* %p)
    170   call void @use_pointer(i8* %p)
    171   %2 = call i8* @objc_autorelease(i8* %p)
    172   ret i8* %p
    173 }
    174 
    175 ; Don't spoil the RV optimization.
    176 
    177 ; CHECK: define i8* @test12(i8* %p)
    178 ; CHECK: tail call i8* @objc_retain(i8* %p)
    179 ; CHECK: call void @use_pointer(i8* %p)
    180 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    181 ; CHECK: ret i8* %p
    182 define i8* @test12(i8* %p) {
    183   %1 = call i8* @objc_retain(i8* %p)
    184   call void @use_pointer(i8* %p)
    185   %2 = call i8* @objc_autoreleaseReturnValue(i8* %p)
    186   ret i8* %p
    187 }
    188 
    189 ; Don't zap the objc_retainAutoreleasedReturnValue.
    190 
    191 ; CHECK-LABEL: define i8* @test13(
    192 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    193 ; CHECK: call i8* @objc_autorelease(i8* %p)
    194 ; CHECK: ret i8* %p
    195 define i8* @test13() {
    196   %p = call i8* @returner()
    197   %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    198   call void @callee()
    199   %2 = call i8* @objc_autorelease(i8* %p)
    200   ret i8* %p
    201 }
    202 
    203 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
    204 ; argument is not a return value.
    205 
    206 ; CHECK-LABEL: define void @test14(
    207 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) [[NUW]]
    208 ; CHECK-NEXT: ret void
    209 define void @test14(i8* %p) {
    210   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    211   ret void
    212 }
    213 
    214 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
    215 ; argument is a return value.
    216 
    217 ; CHECK-LABEL: define void @test15(
    218 ; CHECK-NEXT: %y = call i8* @returner()
    219 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]]
    220 ; CHECK-NEXT: ret void
    221 define void @test15() {
    222   %y = call i8* @returner()
    223   call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
    224   ret void
    225 }
    226 
    227 ; Delete autoreleaseRV+retainRV pairs.
    228 
    229 ; CHECK: define i8* @test19(i8* %p) {
    230 ; CHECK-NEXT: ret i8* %p
    231 define i8* @test19(i8* %p) {
    232   call i8* @objc_autoreleaseReturnValue(i8* %p)
    233   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    234   ret i8* %p
    235 }
    236 
    237 ; Like test19 but with plain autorelease.
    238 
    239 ; CHECK: define i8* @test20(i8* %p) {
    240 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
    241 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
    242 ; CHECK-NEXT: ret i8* %p
    243 define i8* @test20(i8* %p) {
    244   call i8* @objc_autorelease(i8* %p)
    245   call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    246   ret i8* %p
    247 }
    248 
    249 ; Like test19 but with plain retain.
    250 
    251 ; CHECK: define i8* @test21(i8* %p) {
    252 ; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p)
    253 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
    254 ; CHECK-NEXT: ret i8* %p
    255 define i8* @test21(i8* %p) {
    256   call i8* @objc_autoreleaseReturnValue(i8* %p)
    257   call i8* @objc_retain(i8* %p)
    258   ret i8* %p
    259 }
    260 
    261 ; Like test19 but with plain retain and autorelease.
    262 
    263 ; CHECK: define i8* @test22(i8* %p) {
    264 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
    265 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
    266 ; CHECK-NEXT: ret i8* %p
    267 define i8* @test22(i8* %p) {
    268   call i8* @objc_autorelease(i8* %p)
    269   call i8* @objc_retain(i8* %p)
    270   ret i8* %p
    271 }
    272 
    273 ; Convert autoreleaseRV to autorelease.
    274 
    275 ; CHECK-LABEL: define void @test23(
    276 ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]]
    277 define void @test23(i8* %p) {
    278   store i8 0, i8* %p
    279   call i8* @objc_autoreleaseReturnValue(i8* %p)
    280   ret void
    281 }
    282 
    283 ; Don't convert autoreleaseRV to autorelease if the result is returned,
    284 ; even through a bitcast.
    285 
    286 ; CHECK-LABEL: define {}* @test24(
    287 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    288 define {}* @test24(i8* %p) {
    289   %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
    290   %s = bitcast i8* %p to {}*
    291   ret {}* %s
    292 }
    293 
    294 ; CHECK: attributes [[NUW]] = { nounwind }
    295