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