Home | History | Annotate | Download | only in ObjCARC
      1 ; RUN: opt -objc-arc -S < %s | FileCheck %s
      2 
      3 target datalayout = "e-p:64:64:64"
      4 
      5 !0 = metadata !{}
      6 
      7 declare i8* @objc_retain(i8*)
      8 declare void @callee(i8)
      9 declare void @use_pointer(i8*)
     10 declare void @objc_release(i8*)
     11 declare i8* @objc_retainBlock(i8*)
     12 declare i8* @objc_autorelease(i8*)
     13 
     14 ; Basic retainBlock+release elimination.
     15 
     16 ; CHECK: define void @test0(i8* %tmp) {
     17 ; CHECK-NOT: @objc
     18 ; CHECK: }
     19 define void @test0(i8* %tmp) {
     20 entry:
     21   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
     22   tail call void @use_pointer(i8* %tmp2)
     23   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
     24   ret void
     25 }
     26 
     27 ; Same as test0, but there's no copy_on_escape metadata, so there's no
     28 ; optimization possible.
     29 
     30 ; CHECK: define void @test0_no_metadata(i8* %tmp) {
     31 ; CHECK: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW:#[0-9]+]]
     32 ; CHECK: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
     33 ; CHECK: }
     34 define void @test0_no_metadata(i8* %tmp) {
     35 entry:
     36   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind
     37   tail call void @use_pointer(i8* %tmp2)
     38   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
     39   ret void
     40 }
     41 
     42 ; Same as test0, but the pointer escapes, so there's no
     43 ; optimization possible.
     44 
     45 ; CHECK: define void @test0_escape(i8* %tmp, i8** %z) {
     46 ; CHECK: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]], !clang.arc.copy_on_escape !0
     47 ; CHECK: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
     48 ; CHECK: }
     49 define void @test0_escape(i8* %tmp, i8** %z) {
     50 entry:
     51   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
     52   store i8* %tmp2, i8** %z
     53   tail call void @use_pointer(i8* %tmp2)
     54   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
     55   ret void
     56 }
     57 
     58 ; Same as test0_escape, but there's no intervening call.
     59 
     60 ; CHECK: define void @test0_just_escape(i8* %tmp, i8** %z) {
     61 ; CHECK: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]], !clang.arc.copy_on_escape !0
     62 ; CHECK: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
     63 ; CHECK: }
     64 define void @test0_just_escape(i8* %tmp, i8** %z) {
     65 entry:
     66   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
     67   store i8* %tmp2, i8** %z
     68   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
     69   ret void
     70 }
     71 
     72 ; Basic nested retainBlock+release elimination.
     73 
     74 ; CHECK: define void @test1(i8* %tmp) {
     75 ; CHECK-NOT: @objc
     76 ; CHECK: tail call i8* @objc_retain(i8* %tmp) [[NUW]]
     77 ; CHECK-NOT: @objc
     78 ; CHECK: tail call void @objc_release(i8* %tmp) [[NUW]], !clang.imprecise_release !0
     79 ; CHECK-NOT: @objc
     80 ; CHECK: }
     81 define void @test1(i8* %tmp) {
     82 entry:
     83   %tmp1 = tail call i8* @objc_retain(i8* %tmp) nounwind
     84   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
     85   tail call void @use_pointer(i8* %tmp2)
     86   tail call void @use_pointer(i8* %tmp2)
     87   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
     88   tail call void @objc_release(i8* %tmp) nounwind, !clang.imprecise_release !0
     89   ret void
     90 }
     91 
     92 ; Same as test1, but there's no copy_on_escape metadata, so there's no
     93 ; retainBlock+release optimization possible. But we can still eliminate
     94 ; the outer retain+release.
     95 
     96 ; CHECK: define void @test1_no_metadata(i8* %tmp) {
     97 ; CHECK-NEXT: entry:
     98 ; CHECK-NEXT: tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]]
     99 ; CHECK-NEXT: @use_pointer(i8* %tmp2)
    100 ; CHECK-NEXT: @use_pointer(i8* %tmp2)
    101 ; CHECK-NEXT: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
    102 ; CHECK-NOT: @objc
    103 ; CHECK: }
    104 define void @test1_no_metadata(i8* %tmp) {
    105 entry:
    106   %tmp1 = tail call i8* @objc_retain(i8* %tmp) nounwind
    107   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind
    108   tail call void @use_pointer(i8* %tmp2)
    109   tail call void @use_pointer(i8* %tmp2)
    110   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
    111   tail call void @objc_release(i8* %tmp) nounwind, !clang.imprecise_release !0
    112   ret void
    113 }
    114 
    115 ; Same as test1, but the pointer escapes, so there's no
    116 ; retainBlock+release optimization possible. But we can still eliminate
    117 ; the outer retain+release
    118 
    119 ; CHECK: define void @test1_escape(i8* %tmp, i8** %z) {
    120 ; CHECK-NEXT: entry:
    121 ; CHECK-NEXT: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]], !clang.arc.copy_on_escape !0
    122 ; CHECK-NEXT: store i8* %tmp2, i8** %z
    123 ; CHECK-NEXT: @use_pointer(i8* %tmp2)
    124 ; CHECK-NEXT: @use_pointer(i8* %tmp2)
    125 ; CHECK-NEXT: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
    126 ; CHECK-NOT: @objc
    127 ; CHECK: }
    128 define void @test1_escape(i8* %tmp, i8** %z) {
    129 entry:
    130   %tmp1 = tail call i8* @objc_retain(i8* %tmp) nounwind
    131   %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
    132   store i8* %tmp2, i8** %z
    133   tail call void @use_pointer(i8* %tmp2)
    134   tail call void @use_pointer(i8* %tmp2)
    135   tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
    136   tail call void @objc_release(i8* %tmp) nounwind, !clang.imprecise_release !0
    137   ret void
    138 }
    139 
    140 ; CHECK: attributes [[NUW]] = { nounwind }
    141