Home | History | Annotate | Download | only in ObjCARC
      1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
      2 
      3 declare i8* @objc_retain(i8*)
      4 declare void @objc_release(i8*)
      5 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
      6 declare i8* @objc_msgSend(i8*, i8*, ...)
      7 declare void @use_pointer(i8*)
      8 declare void @callee()
      9 declare i8* @returner()
     10 
     11 ; ARCOpt shouldn't try to move the releases to the block containing the invoke.
     12 
     13 ; CHECK: define void @test0(
     14 ; CHECK: invoke.cont:
     15 ; CHECK:   call void @objc_release(i8* %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
     16 ; CHECK:   ret void
     17 ; CHECK: lpad:
     18 ; CHECK:   call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
     19 ; CHECK:   ret void
     20 define void @test0(i8* %zipFile) {
     21 entry:
     22   call i8* @objc_retain(i8* %zipFile) nounwind
     23   call void @use_pointer(i8* %zipFile)
     24   invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile) 
     25           to label %invoke.cont unwind label %lpad
     26 
     27 invoke.cont:                                      ; preds = %entry
     28   call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
     29   ret void
     30 
     31 lpad:                                             ; preds = %entry
     32   %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
     33            cleanup
     34   call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
     35   ret void
     36 }
     37 
     38 ; ARCOpt should move the release before the callee calls.
     39 
     40 ; CHECK: define void @test1(
     41 ; CHECK: invoke.cont:
     42 ; CHECK:   call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
     43 ; CHECK:   call void @callee()
     44 ; CHECK:   br label %done
     45 ; CHECK: lpad:
     46 ; CHECK:   call void @objc_release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
     47 ; CHECK:   call void @callee()
     48 ; CHECK:   br label %done
     49 ; CHECK: done:
     50 ; CHECK-NEXT: ret void
     51 define void @test1(i8* %zipFile) {
     52 entry:
     53   call i8* @objc_retain(i8* %zipFile) nounwind
     54   call void @use_pointer(i8* %zipFile)
     55   invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
     56           to label %invoke.cont unwind label %lpad
     57 
     58 invoke.cont:                                      ; preds = %entry
     59   call void @callee()
     60   br label %done
     61 
     62 lpad:                                             ; preds = %entry
     63   %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
     64            cleanup
     65   call void @callee()
     66   br label %done
     67 
     68 done:
     69   call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0
     70   ret void
     71 }
     72 
     73 ; The optimizer should ignore invoke unwind paths consistently.
     74 ; PR12265
     75 
     76 ; CHECK: define void @test2() {
     77 ; CHECK: invoke.cont:
     78 ; CHECK-NEXT: call i8* @objc_retain
     79 ; CHECK-NOT: @objc_r
     80 ; CHECK: finally.cont:
     81 ; CHECK-NEXT: call void @objc_release
     82 ; CHECK-NOT: @objc
     83 ; CHECK: finally.rethrow:
     84 ; CHECK-NOT: @objc
     85 ; CHECK: }
     86 define void @test2() {
     87 entry:
     88   %call = invoke i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* ()*)()
     89           to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
     90 
     91 invoke.cont:                                      ; preds = %entry
     92   %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
     93   call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void ()*)(), !clang.arc.no_objc_arc_exceptions !0
     94   invoke void @use_pointer(i8* %call)
     95           to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0
     96 
     97 finally.cont:                                     ; preds = %invoke.cont
     98   tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0
     99   ret void
    100 
    101 finally.rethrow:                                  ; preds = %invoke.cont, %entry
    102   %tmp2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
    103           catch i8* null
    104   unreachable
    105 }
    106 
    107 ; Don't try to place code on invoke critical edges.
    108 
    109 ; CHECK: define void @test3(
    110 ; CHECK: if.end:
    111 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
    112 ; CHECK-NEXT: ret void
    113 define void @test3(i8* %p, i1 %b) {
    114 entry:
    115   %0 = call i8* @objc_retain(i8* %p)
    116   call void @callee()
    117   br i1 %b, label %if.else, label %if.then
    118 
    119 if.then:
    120   invoke void @use_pointer(i8* %p)
    121           to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
    122 
    123 if.else:
    124   invoke void @use_pointer(i8* %p)
    125           to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
    126 
    127 lpad:
    128   %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
    129        cleanup
    130   ret void
    131 
    132 if.end:
    133   call void @objc_release(i8* %p)
    134   ret void
    135 }
    136 
    137 ; Like test3, but with ARC-relevant exception handling.
    138 
    139 ; CHECK: define void @test4(
    140 ; CHECK: lpad:
    141 ; CHECK-NEXT: %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
    142 ; CHECK-NEXT: cleanup
    143 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
    144 ; CHECK-NEXT: ret void
    145 ; CHECK: if.end:
    146 ; CHECK-NEXT: call void @objc_release(i8* %p) [[NUW]]
    147 ; CHECK-NEXT: ret void
    148 define void @test4(i8* %p, i1 %b) {
    149 entry:
    150   %0 = call i8* @objc_retain(i8* %p)
    151   call void @callee()
    152   br i1 %b, label %if.else, label %if.then
    153 
    154 if.then:
    155   invoke void @use_pointer(i8* %p)
    156           to label %if.end unwind label %lpad
    157 
    158 if.else:
    159   invoke void @use_pointer(i8* %p)
    160           to label %if.end unwind label %lpad
    161 
    162 lpad:
    163   %r = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
    164        cleanup
    165   call void @objc_release(i8* %p)
    166   ret void
    167 
    168 if.end:
    169   call void @objc_release(i8* %p)
    170   ret void
    171 }
    172 
    173 ; Don't turn the retainAutoreleaseReturnValue into retain, because it's
    174 ; for an invoke which we can assume codegen will put immediately prior.
    175 
    176 ; CHECK: define void @test5(
    177 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
    178 ; CHECK: }
    179 define void @test5() {
    180 entry:
    181   %z = invoke i8* @returner()
    182           to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
    183 
    184 lpad:
    185   %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
    186           cleanup
    187   ret void
    188 
    189 if.end:
    190   call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
    191   ret void
    192 }
    193 
    194 ; Like test5, but there's intervening code.
    195 
    196 ; CHECK: define void @test6(
    197 ; CHECK: call i8* @objc_retain(i8* %z)
    198 ; CHECK: }
    199 define void @test6() {
    200 entry:
    201   %z = invoke i8* @returner()
    202           to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
    203 
    204 lpad:
    205   %r13 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
    206           cleanup
    207   ret void
    208 
    209 if.end:
    210   call void @callee()
    211   call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
    212   ret void
    213 }
    214 
    215 declare i32 @__gxx_personality_v0(...)
    216 declare i32 @__objc_personality_v0(...)
    217 
    218 ; CHECK: attributes [[NUW]] = { nounwind }
    219 
    220 !0 = metadata !{}
    221