Home | History | Annotate | Download | only in ObjCARC
      1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
      2 
      3 declare i8* @objc_retain(i8*) nonlazybind
      4 declare void @objc_release(i8*) nonlazybind
      5 declare i8* @objc_retainBlock(i8*)
      6 
      7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      8 ; Use by an instruction which copies the value is an escape if the             ;
      9 ; result is an escape. The current instructions with this property are:        ;
     10 ;                                                                              ;
     11 ; 1. BitCast.                                                                  ;
     12 ; 2. GEP.                                                                      ;
     13 ; 3. PhiNode.                                                                  ;
     14 ; 4. SelectInst.                                                               ;
     15 ;                                                                              ;
     16 ; Make sure that such instructions do not confuse the optimizer into removing  ;
     17 ; an objc_retainBlock that is needed.                                          ;
     18 ;                                                                              ;
     19 ; rdar://13273675. (With extra test cases to handle bitcast, phi, and select.  ;
     20 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     21 
     22 define void @bitcasttest(i8* %storage, void (...)* %block)  {
     23 ; CHECK-LABEL: define void @bitcasttest(
     24 entry:
     25   %t1 = bitcast void (...)* %block to i8*
     26 ; CHECK: tail call i8* @objc_retain
     27   %t2 = tail call i8* @objc_retain(i8* %t1)
     28 ; CHECK: tail call i8* @objc_retainBlock
     29   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
     30   %t4 = bitcast i8* %storage to void (...)**
     31   %t5 = bitcast i8* %t3 to void (...)*
     32   store void (...)* %t5, void (...)** %t4, align 8
     33 ; CHECK: call void @objc_release
     34   call void @objc_release(i8* %t1)
     35   ret void
     36 ; CHECK: }
     37 }
     38 
     39 define void @bitcasttest_a(i8* %storage, void (...)* %block)  {
     40 ; CHECK-LABEL: define void @bitcasttest_a(
     41 entry:
     42   %t1 = bitcast void (...)* %block to i8*
     43 ; CHECK-NOT: tail call i8* @objc_retain
     44   %t2 = tail call i8* @objc_retain(i8* %t1)
     45 ; CHECK: tail call i8* @objc_retainBlock
     46   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
     47   %t4 = bitcast i8* %storage to void (...)**
     48   %t5 = bitcast i8* %t3 to void (...)*
     49   store void (...)* %t5, void (...)** %t4, align 8
     50 ; CHECK-NOT: call void @objc_release
     51   call void @objc_release(i8* %t1), !clang.imprecise_release !0
     52   ret void
     53 ; CHECK: }
     54 }
     55 
     56 define void @geptest(void (...)** %storage_array, void (...)* %block)  {
     57 ; CHECK-LABEL: define void @geptest(
     58 entry:
     59   %t1 = bitcast void (...)* %block to i8*
     60 ; CHECK: tail call i8* @objc_retain
     61   %t2 = tail call i8* @objc_retain(i8* %t1)
     62 ; CHECK: tail call i8* @objc_retainBlock
     63   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
     64   %t4 = bitcast i8* %t3 to void (...)*
     65   
     66   %storage = getelementptr inbounds void (...)** %storage_array, i64 0
     67   
     68   store void (...)* %t4, void (...)** %storage, align 8
     69 ; CHECK: call void @objc_release
     70   call void @objc_release(i8* %t1)
     71   ret void
     72 ; CHECK: }
     73 }
     74 
     75 define void @geptest_a(void (...)** %storage_array, void (...)* %block)  {
     76 ; CHECK-LABEL: define void @geptest_a(
     77 entry:
     78   %t1 = bitcast void (...)* %block to i8*
     79 ; CHECK-NOT: tail call i8* @objc_retain
     80   %t2 = tail call i8* @objc_retain(i8* %t1)
     81 ; CHECK: tail call i8* @objc_retainBlock
     82   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
     83   %t4 = bitcast i8* %t3 to void (...)*
     84   
     85   %storage = getelementptr inbounds void (...)** %storage_array, i64 0
     86   
     87   store void (...)* %t4, void (...)** %storage, align 8
     88 ; CHECK-NOT: call void @objc_release
     89   call void @objc_release(i8* %t1), !clang.imprecise_release !0
     90   ret void
     91 ; CHECK: }
     92 }
     93 
     94 define void @selecttest(void (...)** %store1, void (...)** %store2,
     95                         void (...)* %block) {
     96 ; CHECK-LABEL: define void @selecttest(
     97 entry:
     98   %t1 = bitcast void (...)* %block to i8*
     99 ; CHECK: tail call i8* @objc_retain
    100   %t2 = tail call i8* @objc_retain(i8* %t1)
    101 ; CHECK: tail call i8* @objc_retainBlock
    102   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
    103   %t4 = bitcast i8* %t3 to void (...)*
    104   %store = select i1 undef, void (...)** %store1, void (...)** %store2
    105   store void (...)* %t4, void (...)** %store, align 8
    106 ; CHECK: call void @objc_release
    107   call void @objc_release(i8* %t1)
    108   ret void
    109 ; CHECK: }
    110 }
    111 
    112 define void @selecttest_a(void (...)** %store1, void (...)** %store2,
    113                           void (...)* %block) {
    114 ; CHECK-LABEL: define void @selecttest_a(
    115 entry:
    116   %t1 = bitcast void (...)* %block to i8*
    117 ; CHECK-NOT: tail call i8* @objc_retain
    118   %t2 = tail call i8* @objc_retain(i8* %t1)
    119 ; CHECK: tail call i8* @objc_retainBlock
    120   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
    121   %t4 = bitcast i8* %t3 to void (...)*
    122   %store = select i1 undef, void (...)** %store1, void (...)** %store2
    123   store void (...)* %t4, void (...)** %store, align 8
    124 ; CHECK-NOT: call void @objc_release
    125   call void @objc_release(i8* %t1), !clang.imprecise_release !0
    126   ret void
    127 ; CHECK: }
    128 }
    129 
    130 define void @phinodetest(void (...)** %storage1,
    131                          void (...)** %storage2,
    132                          void (...)* %block) {
    133 ; CHECK-LABEL: define void @phinodetest(
    134 entry:
    135   %t1 = bitcast void (...)* %block to i8*
    136 ; CHECK: tail call i8* @objc_retain
    137   %t2 = tail call i8* @objc_retain(i8* %t1)
    138 ; CHECK: tail call i8* @objc_retainBlock
    139   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
    140   %t4 = bitcast i8* %t3 to void (...)*
    141   br i1 undef, label %store1_set, label %store2_set
    142 ; CHECK: store1_set:
    143 
    144 store1_set:
    145   br label %end
    146 
    147 store2_set:
    148   br label %end
    149 
    150 end:
    151 ; CHECK: end:
    152   %storage = phi void (...)** [ %storage1, %store1_set ], [ %storage2, %store2_set]
    153   store void (...)* %t4, void (...)** %storage, align 8
    154 ; CHECK: call void @objc_release
    155   call void @objc_release(i8* %t1)
    156   ret void
    157 ; CHECK: }
    158 }
    159 
    160 define void @phinodetest_a(void (...)** %storage1,
    161                            void (...)** %storage2,
    162                            void (...)* %block) {
    163 ; CHECK-LABEL: define void @phinodetest_a(
    164 entry:
    165   %t1 = bitcast void (...)* %block to i8*
    166 ; CHECK-NOT: tail call i8* @objc_retain
    167   %t2 = tail call i8* @objc_retain(i8* %t1)
    168 ; CHECK: tail call i8* @objc_retainBlock
    169   %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
    170   %t4 = bitcast i8* %t3 to void (...)*
    171   br i1 undef, label %store1_set, label %store2_set
    172 
    173 store1_set:
    174   br label %end
    175 
    176 store2_set:
    177   br label %end
    178 
    179 end:
    180   %storage = phi void (...)** [ %storage1, %store1_set ], [ %storage2, %store2_set]
    181   store void (...)* %t4, void (...)** %storage, align 8
    182 ; CHECK-NOT: call void @objc_release
    183   call void @objc_release(i8* %t1), !clang.imprecise_release !0
    184   ret void
    185 }
    186 
    187 
    188 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    189 ; This test makes sure that we do not hang clang when visiting a use ;
    190 ; cycle caused by phi nodes during objc-arc analysis. *NOTE* This    ;
    191 ; test case looks a little convoluted since it was produced by	     ;
    192 ; bugpoint.							     ;
    193 ; 								     ;
    194 ; bugzilla://14551						     ;
    195 ; rdar://12851911						     ;
    196 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    197 
    198 define void @phinode_use_cycle(i8* %block) uwtable optsize ssp {
    199 ; CHECK: define void @phinode_use_cycle(i8* %block)
    200 entry:
    201   br label %for.body
    202 
    203 for.body:                                         ; preds = %if.then, %for.body, %entry
    204   %block.05 = phi void (...)* [ null, %entry ], [ %1, %if.then ], [ %block.05, %for.body ]
    205   br i1 undef, label %for.body, label %if.then
    206 
    207 if.then:                                          ; preds = %for.body
    208   %0 = call i8* @objc_retainBlock(i8* %block), !clang.arc.copy_on_escape !0
    209   %1 = bitcast i8* %0 to void (...)*
    210   %2 = bitcast void (...)* %block.05 to i8*
    211   call void @objc_release(i8* %2) nounwind, !clang.imprecise_release !0
    212   br label %for.body
    213 }
    214 
    215 !0 = metadata !{}
    216