Home | History | Annotate | Download | only in ObjCARC
      1 ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
      2 
      3 target datalayout = "e-p:64:64:64"
      4 
      5 declare i8* @objc_retain(i8*)
      6 declare void @objc_release(i8*)
      7 declare i8* @objc_autorelease(i8*)
      8 declare i8* @objc_autoreleaseReturnValue(i8*)
      9 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
     10 
     11 declare void @use_pointer(i8*)
     12 declare i8* @returner()
     13 
     14 ; CHECK: define void @test0
     15 ; CHECK: call void @use_pointer(i8* %0)
     16 ; CHECK: }
     17 define void @test0(i8* %x) nounwind {
     18 entry:
     19   %0 = call i8* @objc_retain(i8* %x) nounwind
     20   call void @use_pointer(i8* %x)
     21   ret void
     22 }
     23 
     24 ; CHECK: define void @test1
     25 ; CHECK: call void @use_pointer(i8* %0)
     26 ; CHECK: }
     27 define void @test1(i8* %x) nounwind {
     28 entry:
     29   %0 = call i8* @objc_autorelease(i8* %x) nounwind
     30   call void @use_pointer(i8* %x)
     31   ret void
     32 }
     33 
     34 ; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
     35 
     36 ; CHECK: define void @test2(
     37 ; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW:#[0-9]+]]
     38 ; CHECK: }
     39 define void @test2(i8* %x) nounwind {
     40 entry:
     41   %0 = tail call i8* @objc_retain(i8* %x) nounwind
     42   call i8* @objc_autorelease(i8* %0) nounwind
     43   call void @use_pointer(i8* %x)
     44   ret void
     45 }
     46 
     47 ; Same as test2 but the value is returned. Do an RV optimization.
     48 
     49 ; CHECK: define i8* @test2b(
     50 ; CHECK: tail call i8* @objc_retainAutoreleaseReturnValue(i8* %x) [[NUW]]
     51 ; CHECK: }
     52 define i8* @test2b(i8* %x) nounwind {
     53 entry:
     54   %0 = tail call i8* @objc_retain(i8* %x) nounwind
     55   tail call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
     56   ret i8* %x
     57 }
     58 
     59 ; Merge a retain,autorelease pair around a call.
     60 
     61 ; CHECK: define void @test3(
     62 ; CHECK: tail call i8* @objc_retainAutorelease(i8* %x) [[NUW]]
     63 ; CHECK: @use_pointer(i8* %0)
     64 ; CHECK: }
     65 define void @test3(i8* %x, i64 %n) {
     66 entry:
     67   tail call i8* @objc_retain(i8* %x) nounwind
     68   call void @use_pointer(i8* %x)
     69   call i8* @objc_autorelease(i8* %x) nounwind
     70   ret void
     71 }
     72 
     73 ; Trivial retain,autorelease pair with intervening call, but it's post-dominated
     74 ; by another release. The retain and autorelease can be merged.
     75 
     76 ; CHECK: define void @test4(
     77 ; CHECK-NEXT: entry:
     78 ; CHECK-NEXT: @objc_retainAutorelease(i8* %x) [[NUW]]
     79 ; CHECK-NEXT: @use_pointer
     80 ; CHECK-NEXT: @objc_release
     81 ; CHECK-NEXT: ret void
     82 ; CHECK-NEXT: }
     83 define void @test4(i8* %x, i64 %n) {
     84 entry:
     85   tail call i8* @objc_retain(i8* %x) nounwind
     86   call void @use_pointer(i8* %x)
     87   call i8* @objc_autorelease(i8* %x) nounwind
     88   tail call void @objc_release(i8* %x) nounwind
     89   ret void
     90 }
     91 
     92 ; Don't merge retain and autorelease if they're not control-equivalent.
     93 
     94 ; CHECK: define void @test5(
     95 ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
     96 ; CHECK: true:
     97 ; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]]
     98 ; CHECK: }
     99 define void @test5(i8* %p, i1 %a) {
    100 entry:
    101   tail call i8* @objc_retain(i8* %p) nounwind
    102   br i1 %a, label %true, label %false
    103 
    104 true:
    105   call i8* @objc_autorelease(i8* %p) nounwind
    106   call void @use_pointer(i8* %p)
    107   ret void
    108 
    109 false:
    110   ret void
    111 }
    112 
    113 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
    114 ; an objc_autorelease.
    115 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
    116 ; objc_retainAutoreleasedReturnValueAutorelease and merge
    117 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
    118 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
    119 ; Those entrypoints don't exist yet though.
    120 
    121 ; CHECK: define i8* @test6(
    122 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p) [[NUW]]
    123 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %1) [[NUW]]
    124 ; CHECK: }
    125 define i8* @test6() {
    126   %p = call i8* @returner()
    127   tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p) nounwind
    128   %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
    129   call void @use_pointer(i8* %t)
    130   ret i8* %t
    131 }
    132 
    133 ; Don't spoil the RV optimization.
    134 
    135 ; CHECK: define i8* @test7(i8* %p)
    136 ; CHECK: tail call i8* @objc_retain(i8* %p)
    137 ; CHECK: call void @use_pointer(i8* %1)
    138 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %1)
    139 ; CHECK: ret i8* %2
    140 define i8* @test7(i8* %p) {
    141   %1 = tail call i8* @objc_retain(i8* %p)
    142   call void @use_pointer(i8* %p)
    143   %2 = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
    144   ret i8* %p
    145 }
    146 
    147 ; Do the return value substitution for PHI nodes too.
    148 
    149 ; CHECK: define i8* @test8(
    150 ; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ]
    151 ; CHECK: }
    152 define i8* @test8(i1 %x, i8* %c) {
    153 entry:
    154   br i1 %x, label %return, label %if.then
    155 
    156 if.then:                                          ; preds = %entry
    157   %p = call i8* @objc_retain(i8* %c) nounwind
    158   br label %return
    159 
    160 return:                                           ; preds = %if.then, %entry
    161   %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
    162   ret i8* %retval
    163 }
    164 
    165 ; CHECK: attributes [[NUW]] = { nounwind }
    166