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