Home | History | Annotate | Download | only in ObjCARC
      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*)
      7 declare i8* @objc_autorelease(i8*)
      8 declare i8* @objc_autoreleaseReturnValue(i8*)
      9 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
     10 
     11 declare void @use_pointer(i8*)
     12 declare i8* @returner()
     13 declare void @callee()
     14 
     15 ; CHECK-LABEL: define void @test0(
     16 ; CHECK: call void @use_pointer(i8* %0)
     17 ; CHECK: }
     18 define void @test0(i8* %x) nounwind {
     19 entry:
     20   %0 = call i8* @objc_retain(i8* %x) nounwind
     21   call void @use_pointer(i8* %x)
     22   ret void
     23 }
     24 
     25 ; CHECK-LABEL: define void @test1(
     26 ; CHECK: call void @use_pointer(i8* %0)
     27 ; CHECK: }
     28 define void @test1(i8* %x) nounwind {
     29 entry:
     30   %0 = call i8* @objc_autorelease(i8* %x) nounwind
     31   call void @use_pointer(i8* %x)
     32   ret void
     33 }
     34 
     35 ; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
     36 
     37 ; CHECK-LABEL: define void @test2(
     38 ; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW:#[0-9]+]]
     39 ; CHECK: }
     40 define void @test2(i8* %x) nounwind {
     41 entry:
     42   %0 = tail call i8* @objc_retain(i8* %x) nounwind
     43   call i8* @objc_autorelease(i8* %0) nounwind
     44   call void @use_pointer(i8* %x)
     45   ret void
     46 }
     47 
     48 ; Same as test2 but the value is returned. Do an RV optimization.
     49 
     50 ; CHECK-LABEL: define i8* @test2b(
     51 ; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) [[NUW]]
     52 ; CHECK: }
     53 define i8* @test2b(i8* %x) nounwind {
     54 entry:
     55   %0 = tail call i8* @objc_retain(i8* %x) nounwind
     56   tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
     57   ret i8* %x
     58 }
     59 
     60 ; Merge a retain,autorelease pair around a call.
     61 
     62 ; CHECK-LABEL: define void @test3(
     63 ; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW]]
     64 ; CHECK: @use_pointer(i8* %0)
     65 ; CHECK: }
     66 define void @test3(i8* %x, i64 %n) {
     67 entry:
     68   tail call i8* @objc_retain(i8* %x) nounwind
     69   call void @use_pointer(i8* %x)
     70   call i8* @objc_autorelease(i8* %x) nounwind
     71   ret void
     72 }
     73 
     74 ; Trivial retain,autorelease pair with intervening call, but it's post-dominated
     75 ; by another release. The retain and autorelease can be merged.
     76 
     77 ; CHECK-LABEL: define void @test4(
     78 ; CHECK-NEXT: entry:
     79 ; CHECK-NEXT: @objc_retainAutorelease(i8* %x) [[NUW]]
     80 ; CHECK-NEXT: @use_pointer
     81 ; CHECK-NEXT: @objc_release
     82 ; CHECK-NEXT: ret void
     83 ; CHECK-NEXT: }
     84 define void @test4(i8* %x, i64 %n) {
     85 entry:
     86   tail call i8* @objc_retain(i8* %x) nounwind
     87   call void @use_pointer(i8* %x)
     88   call i8* @objc_autorelease(i8* %x) nounwind
     89   tail call void @objc_release(i8* %x) nounwind
     90   ret void
     91 }
     92 
     93 ; Don't merge retain and autorelease if they're not control-equivalent.
     94 
     95 ; CHECK-LABEL: define void @test5(
     96 ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
     97 ; CHECK: true:
     98 ; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]]
     99 ; CHECK: }
    100 define void @test5(i8* %p, i1 %a) {
    101 entry:
    102   tail call i8* @objc_retain(i8* %p) nounwind
    103   br i1 %a, label %true, label %false
    104 
    105 true:
    106   call i8* @objc_autorelease(i8* %p) nounwind
    107   call void @use_pointer(i8* %p)
    108   ret void
    109 
    110 false:
    111   ret void
    112 }
    113 
    114 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
    115 ; an objc_autorelease.
    116 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
    117 ; objc_retainAutoreleasedReturnValueAutorelease and merge
    118 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
    119 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
    120 ; Those entrypoints don't exist yet though.
    121 
    122 ; CHECK-LABEL: define i8* @test6(
    123 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) [[NUW]]
    124 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) [[NUW]]
    125 ; CHECK: }
    126 define i8* @test6() {
    127   %p = call i8* @returner()
    128   tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
    129   %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
    130   call void @use_pointer(i8* %t)
    131   ret i8* %t
    132 }
    133 
    134 ; Don't spoil the RV optimization.
    135 
    136 ; CHECK: define i8* @test7(i8* %p)
    137 ; CHECK: tail call i8* @objc_retain(i8* %p)
    138 ; CHECK: call void @use_pointer(i8* %1)
    139 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1)
    140 ; CHECK: ret i8* %2
    141 ; CHECK-NEXT: }
    142 define i8* @test7(i8* %p) {
    143   %1 = tail call i8* @objc_retain(i8* %p)
    144   call void @use_pointer(i8* %p)
    145   %2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    146   ret i8* %p
    147 }
    148 
    149 ; Do the return value substitution for PHI nodes too.
    150 
    151 ; CHECK-LABEL: define i8* @test8(
    152 ; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ]
    153 ; CHECK: }
    154 define i8* @test8(i1 %x, i8* %c) {
    155 entry:
    156   br i1 %x, label %return, label %if.then
    157 
    158 if.then:                                          ; preds = %entry
    159   %p = call i8* @objc_retain(i8* %c) nounwind
    160   br label %return
    161 
    162 return:                                           ; preds = %if.then, %entry
    163   %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
    164   ret i8* %retval
    165 }
    166 
    167 ; Kill calls to @clang.arc.use(...)
    168 ; CHECK-LABEL: define void @test9(
    169 ; CHECK-NOT: clang.arc.use
    170 ; CHECK: }
    171 define void @test9(i8* %a, i8* %b) {
    172   call void (...) @clang.arc.use(i8* %a, i8* %b) nounwind
    173   ret void
    174 }
    175 
    176 
    177 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
    178 ; is a return value.
    179 
    180 ; CHECK: define void @test10()
    181 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
    182 define void @test10() {
    183   %p = call i8* @returner()
    184   tail call i8* @objc_retain(i8* %p) nounwind
    185   ret void
    186 }
    187 
    188 ; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
    189 ; argument is a return value.
    190 
    191 ; CHECK-LABEL: define void @test11(
    192 ; CHECK-NEXT: %y = call i8* @returner()
    193 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]]
    194 ; CHECK-NEXT: ret void
    195 define void @test11() {
    196   %y = call i8* @returner()
    197   tail call i8* @objc_retain(i8* %y) nounwind
    198   ret void
    199 }
    200 
    201 ; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
    202 ; argument is not a return value.
    203 
    204 ; CHECK-LABEL: define void @test12(
    205 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) [[NUW]]
    206 ; CHECK-NEXT: ret void
    207 ; CHECK-NEXT: }
    208 define void @test12(i8* %y) {
    209   tail call i8* @objc_retain(i8* %y) nounwind
    210   ret void
    211 }
    212 
    213 ; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
    214 ; isn't next to the call providing its return value.
    215 
    216 ; CHECK-LABEL: define void @test13(
    217 ; CHECK-NEXT: %y = call i8* @returner()
    218 ; CHECK-NEXT: call void @callee()
    219 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) [[NUW]]
    220 ; CHECK-NEXT: ret void
    221 ; CHECK-NEXT: }
    222 define void @test13() {
    223   %y = call i8* @returner()
    224   call void @callee()
    225   tail call i8* @objc_retain(i8* %y) nounwind
    226   ret void
    227 }
    228 
    229 
    230 declare void @clang.arc.use(...) nounwind
    231 
    232 ; CHECK: attributes [[NUW]] = { nounwind }
    233