Home | History | Annotate | Download | only in ObjCARC
      1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
      2 ; rdar://9503416
      3 
      4 ; Detect loop boundaries and don't move retains and releases
      5 ; across them.
      6 
      7 declare void @use_pointer(i8*)
      8 declare i8* @objc_retain(i8*)
      9 declare void @objc_release(i8*)
     10 declare void @callee()
     11 
     12 ; CHECK: define void @test0(
     13 ; CHECK:   call i8* @objc_retain(
     14 ; CHECK: for.body:
     15 ; CHECK-NOT: @objc
     16 ; CHECK: for.end:
     17 ; CHECK:   call void @objc_release(
     18 ; CHECK: }
     19 define void @test0(i8* %digits) {
     20 entry:
     21   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
     22   call void @use_pointer(i8* %digits)
     23   br label %for.body
     24 
     25 for.body:                                         ; preds = %for.body, %entry
     26   %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
     27   call void @use_pointer(i8* %digits)
     28   %inc = add i64 %upcDigitIndex.01, 1
     29   %cmp = icmp ult i64 %inc, 12
     30   br i1 %cmp, label %for.body, label %for.end
     31 
     32 for.end:                                          ; preds = %for.body
     33   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
     34   ret void
     35 }
     36 
     37 ; CHECK: define void @test1(
     38 ; CHECK:   call i8* @objc_retain(
     39 ; CHECK: for.body:
     40 ; CHECK-NOT: @objc
     41 ; CHECK: for.end:
     42 ; CHECK:   void @objc_release(
     43 ; CHECK: }
     44 define void @test1(i8* %digits) {
     45 entry:
     46   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
     47   br label %for.body
     48 
     49 for.body:                                         ; preds = %for.body, %entry
     50   %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
     51   call void @use_pointer(i8* %digits)
     52   call void @use_pointer(i8* %digits)
     53   %inc = add i64 %upcDigitIndex.01, 1
     54   %cmp = icmp ult i64 %inc, 12
     55   br i1 %cmp, label %for.body, label %for.end
     56 
     57 for.end:                                          ; preds = %for.body
     58   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
     59   ret void
     60 }
     61 
     62 ; CHECK: define void @test2(
     63 ; CHECK:   call i8* @objc_retain(
     64 ; CHECK: for.body:
     65 ; CHECK-NOT: @objc
     66 ; CHECK: for.end:
     67 ; CHECK:   void @objc_release(
     68 ; CHECK: }
     69 define void @test2(i8* %digits) {
     70 entry:
     71   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
     72   br label %for.body
     73 
     74 for.body:                                         ; preds = %for.body, %entry
     75   %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
     76   call void @use_pointer(i8* %digits)
     77   %inc = add i64 %upcDigitIndex.01, 1
     78   %cmp = icmp ult i64 %inc, 12
     79   br i1 %cmp, label %for.body, label %for.end
     80 
     81 for.end:                                          ; preds = %for.body
     82   call void @use_pointer(i8* %digits)
     83   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
     84   ret void
     85 }
     86 
     87 ; Delete nested retain+release pairs around loops.
     88 
     89 ;      CHECK: define void @test3(i8* %a) nounwind {
     90 ; CHECK-NEXT: entry:
     91 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
     92 ; CHECK-NEXT:   br label %loop
     93 ;  CHECK-NOT:   @objc_
     94 ;      CHECK: exit:
     95 ; CHECK-NEXT:   call void @objc_release(i8* %a)
     96 ; CHECK-NEXT:   ret void
     97 ; CHECK-NEXT: }
     98 define void @test3(i8* %a) nounwind {
     99 entry:
    100   %outer = call i8* @objc_retain(i8* %a) nounwind
    101   %inner = call i8* @objc_retain(i8* %a) nounwind
    102   br label %loop
    103 
    104 loop:
    105   call void @callee()
    106   store i8 0, i8* %a
    107   br i1 undef, label %loop, label %exit
    108 
    109 exit:
    110   call void @objc_release(i8* %a) nounwind
    111   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    112   ret void
    113 }
    114 
    115 ;      CHECK: define void @test4(i8* %a) nounwind {
    116 ; CHECK-NEXT: entry:
    117 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
    118 ; CHECK-NEXT:   br label %loop
    119 ;  CHECK-NOT:   @objc_
    120 ;      CHECK: exit:
    121 ; CHECK-NEXT:   call void @objc_release(i8* %a)
    122 ; CHECK-NEXT:   ret void
    123 ; CHECK-NEXT: }
    124 define void @test4(i8* %a) nounwind {
    125 entry:
    126   %outer = call i8* @objc_retain(i8* %a) nounwind
    127   %inner = call i8* @objc_retain(i8* %a) nounwind
    128   br label %loop
    129 
    130 loop:
    131   br label %more
    132 
    133 more:
    134   call void @callee()
    135   call void @callee()
    136   store i8 0, i8* %a
    137   br i1 undef, label %loop, label %exit
    138 
    139 exit:
    140   call void @objc_release(i8* %a) nounwind
    141   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    142   ret void
    143 }
    144 
    145 ;      CHECK: define void @test5(i8* %a) nounwind {
    146 ; CHECK-NEXT: entry:
    147 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
    148 ; CHECK-NEXT:   call void @callee()
    149 ; CHECK-NEXT:   br label %loop
    150 ;  CHECK-NOT:   @objc_
    151 ;      CHECK: exit:
    152 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
    153 ; CHECK-NEXT:   call void @objc_release(i8* %a)
    154 ; CHECK-NEXT:   ret void
    155 ; CHECK-NEXT: }
    156 define void @test5(i8* %a) nounwind {
    157 entry:
    158   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    159   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    160   call void @callee()
    161   br label %loop
    162 
    163 loop:
    164   br i1 undef, label %true, label %more
    165 
    166 true:
    167   br label %more
    168 
    169 more:
    170   br i1 undef, label %exit, label %loop
    171 
    172 exit:
    173   call void @use_pointer(i8* %a)
    174   call void @objc_release(i8* %a) nounwind
    175   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    176   ret void
    177 }
    178 
    179 ;      CHECK: define void @test6(i8* %a) nounwind {
    180 ; CHECK-NEXT: entry:
    181 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
    182 ; CHECK-NEXT:   br label %loop
    183 ;  CHECK-NOT:   @objc_
    184 ;      CHECK: exit:
    185 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
    186 ; CHECK-NEXT:   call void @objc_release(i8* %a)
    187 ; CHECK-NEXT:   ret void
    188 ; CHECK-NEXT: }
    189 define void @test6(i8* %a) nounwind {
    190 entry:
    191   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    192   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    193   br label %loop
    194 
    195 loop:
    196   br i1 undef, label %true, label %more
    197 
    198 true:
    199   call void @callee()
    200   br label %more
    201 
    202 more:
    203   br i1 undef, label %exit, label %loop
    204 
    205 exit:
    206   call void @use_pointer(i8* %a)
    207   call void @objc_release(i8* %a) nounwind
    208   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    209   ret void
    210 }
    211 
    212 ;      CHECK: define void @test7(i8* %a) nounwind {
    213 ; CHECK-NEXT: entry:
    214 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
    215 ; CHECK-NEXT:   call void @callee()
    216 ; CHECK-NEXT:   br label %loop
    217 ;  CHECK-NOT:   @objc_
    218 ;      CHECK: exit:
    219 ; CHECK-NEXT:   call void @objc_release(i8* %a)
    220 ; CHECK-NEXT:   ret void
    221 ; CHECK-NEXT: }
    222 define void @test7(i8* %a) nounwind {
    223 entry:
    224   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    225   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    226   call void @callee()
    227   br label %loop
    228 
    229 loop:
    230   br i1 undef, label %true, label %more
    231 
    232 true:
    233   call void @use_pointer(i8* %a)
    234   br label %more
    235 
    236 more:
    237   br i1 undef, label %exit, label %loop
    238 
    239 exit:
    240   call void @objc_release(i8* %a) nounwind
    241   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    242   ret void
    243 }
    244 
    245 ;      CHECK: define void @test8(i8* %a) nounwind {
    246 ; CHECK-NEXT: entry:
    247 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
    248 ; CHECK-NEXT:   br label %loop
    249 ;  CHECK-NOT:   @objc_
    250 ;      CHECK: exit:
    251 ; CHECK-NEXT:   call void @objc_release(i8* %a)
    252 ; CHECK-NEXT:   ret void
    253 ; CHECK-NEXT: }
    254 define void @test8(i8* %a) nounwind {
    255 entry:
    256   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    257   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    258   br label %loop
    259 
    260 loop:
    261   br i1 undef, label %true, label %more
    262 
    263 true:
    264   call void @callee()
    265   call void @use_pointer(i8* %a)
    266   br label %more
    267 
    268 more:
    269   br i1 undef, label %exit, label %loop
    270 
    271 exit:
    272   call void @objc_release(i8* %a) nounwind
    273   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    274   ret void
    275 }
    276 
    277 ;      CHECK: define void @test9(i8* %a) nounwind {
    278 ; CHECK-NEXT: entry:
    279 ; CHECK-NEXT:   br label %loop
    280 ;  CHECK-NOT:   @objc_
    281 ;      CHECK: exit:
    282 ; CHECK-NEXT:   ret void
    283 ; CHECK-NEXT: }
    284 define void @test9(i8* %a) nounwind {
    285 entry:
    286   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    287   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    288   br label %loop
    289 
    290 loop:
    291   br i1 undef, label %true, label %more
    292 
    293 true:
    294   call void @use_pointer(i8* %a)
    295   br label %more
    296 
    297 more:
    298   br i1 undef, label %exit, label %loop
    299 
    300 exit:
    301   call void @objc_release(i8* %a) nounwind
    302   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    303   ret void
    304 }
    305 
    306 ;      CHECK: define void @test10(i8* %a) nounwind {
    307 ; CHECK-NEXT: entry:
    308 ; CHECK-NEXT:   br label %loop
    309 ;  CHECK-NOT:   @objc_
    310 ;      CHECK: exit:
    311 ; CHECK-NEXT:   ret void
    312 ; CHECK-NEXT: }
    313 define void @test10(i8* %a) nounwind {
    314 entry:
    315   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    316   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    317   br label %loop
    318 
    319 loop:
    320   br i1 undef, label %true, label %more
    321 
    322 true:
    323   call void @callee()
    324   br label %more
    325 
    326 more:
    327   br i1 undef, label %exit, label %loop
    328 
    329 exit:
    330   call void @objc_release(i8* %a) nounwind
    331   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    332   ret void
    333 }
    334 
    335 ;      CHECK: define void @test11(i8* %a) nounwind {
    336 ; CHECK-NEXT: entry:
    337 ; CHECK-NEXT:   br label %loop
    338 ;  CHECK-NOT:   @objc_
    339 ;      CHECK: exit:
    340 ; CHECK-NEXT:   ret void
    341 ; CHECK-NEXT: }
    342 define void @test11(i8* %a) nounwind {
    343 entry:
    344   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    345   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    346   br label %loop
    347 
    348 loop:
    349   br i1 undef, label %true, label %more
    350 
    351 true:
    352   br label %more
    353 
    354 more:
    355   br i1 undef, label %exit, label %loop
    356 
    357 exit:
    358   call void @objc_release(i8* %a) nounwind
    359   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    360   ret void
    361 }
    362 
    363 ; Don't delete anything if they're not balanced.
    364 
    365 ;      CHECK: define void @test12(i8* %a) nounwind {
    366 ; CHECK-NEXT: entry:
    367 ; CHECK-NEXT:   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    368 ; CHECK-NEXT:   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    369 ; CHECK-NEXT:   br label %loop
    370 ;  CHECK-NOT:   @objc_
    371 ;      CHECK: exit:
    372 ; CHECK-NEXT: call void @objc_release(i8* %a) nounwind
    373 ; CHECK-NEXT: call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    374 ; CHECK-NEXT:   ret void
    375 ; CHECK-NEXT: }
    376 define void @test12(i8* %a) nounwind {
    377 entry:
    378   %outer = tail call i8* @objc_retain(i8* %a) nounwind
    379   %inner = tail call i8* @objc_retain(i8* %a) nounwind
    380   br label %loop
    381 
    382 loop:
    383   br i1 undef, label %true, label %more
    384 
    385 true:
    386   ret void
    387 
    388 more:
    389   br i1 undef, label %exit, label %loop
    390 
    391 exit:
    392   call void @objc_release(i8* %a) nounwind
    393   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
    394   ret void
    395 }
    396 
    397 !0 = metadata !{}
    398