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 void @use_pointer(i8*)
      8 
      9 @x = external global i8*
     10 
     11 ; CHECK-LABEL: define void @test0(
     12 ; CHECK: entry:
     13 ; CHECK-NEXT: tail call void @objc_storeStrong(i8** @x, i8* %p) [[NUW:#[0-9]+]]
     14 ; CHECK-NEXT: ret void
     15 ; CHECK-NEXT: }
     16 define void @test0(i8* %p) {
     17 entry:
     18   %0 = tail call i8* @objc_retain(i8* %p) nounwind
     19   %tmp = load i8** @x, align 8
     20   store i8* %0, i8** @x, align 8
     21   tail call void @objc_release(i8* %tmp) nounwind
     22   ret void
     23 }
     24 
     25 ; Don't do this if the load is volatile.
     26 
     27 ;      CHECK: define void @test1(i8* %p) {
     28 ; CHECK-NEXT: entry:
     29 ; CHECK-NEXT:   %0 = tail call i8* @objc_retain(i8* %p) [[NUW]]
     30 ; CHECK-NEXT:   %tmp = load volatile i8** @x, align 8
     31 ; CHECK-NEXT:   store i8* %0, i8** @x, align 8
     32 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) [[NUW]]
     33 ; CHECK-NEXT:   ret void
     34 ; CHECK-NEXT: }
     35 define void @test1(i8* %p) {
     36 entry:
     37   %0 = tail call i8* @objc_retain(i8* %p) nounwind
     38   %tmp = load volatile i8** @x, align 8
     39   store i8* %0, i8** @x, align 8
     40   tail call void @objc_release(i8* %tmp) nounwind
     41   ret void
     42 }
     43 
     44 ; Don't do this if the store is volatile.
     45 
     46 ;      CHECK: define void @test2(i8* %p) {
     47 ; CHECK-NEXT: entry:
     48 ; CHECK-NEXT:   %0 = tail call i8* @objc_retain(i8* %p) [[NUW]]
     49 ; CHECK-NEXT:   %tmp = load i8** @x, align 8
     50 ; CHECK-NEXT:   store volatile i8* %0, i8** @x, align 8
     51 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) [[NUW]]
     52 ; CHECK-NEXT:   ret void
     53 ; CHECK-NEXT: }
     54 define void @test2(i8* %p) {
     55 entry:
     56   %0 = tail call i8* @objc_retain(i8* %p) nounwind
     57   %tmp = load i8** @x, align 8
     58   store volatile i8* %0, i8** @x, align 8
     59   tail call void @objc_release(i8* %tmp) nounwind
     60   ret void
     61 }
     62 
     63 ; Don't do this if there's a use of the old pointer value between the store
     64 ; and the release.
     65 
     66 ; CHECK:      define void @test3(i8* %newValue) {
     67 ; CHECK-NEXT: entry:
     68 ; CHECK-NEXT:   %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]]
     69 ; CHECK-NEXT:   %x1 = load i8** @x, align 8
     70 ; CHECK-NEXT:   store i8* %x0, i8** @x, align 8
     71 ; CHECK-NEXT:   tail call void @use_pointer(i8* %x1), !clang.arc.no_objc_arc_exceptions !0
     72 ; CHECK-NEXT:   tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0
     73 ; CHECK-NEXT:   ret void
     74 ; CHECK-NEXT: }
     75 define void @test3(i8* %newValue) {
     76 entry:
     77   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
     78   %x1 = load i8** @x, align 8
     79   store i8* %newValue, i8** @x, align 8
     80   tail call void @use_pointer(i8* %x1), !clang.arc.no_objc_arc_exceptions !0
     81   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
     82   ret void
     83 }
     84 
     85 ; Like test3, but with an icmp use instead of a call, for good measure.
     86 
     87 ; CHECK:      define i1 @test4(i8* %newValue, i8* %foo) {
     88 ; CHECK-NEXT: entry:
     89 ; CHECK-NEXT:   %x0 = tail call i8* @objc_retain(i8* %newValue) [[NUW]]
     90 ; CHECK-NEXT:   %x1 = load i8** @x, align 8
     91 ; CHECK-NEXT:   store i8* %x0, i8** @x, align 8
     92 ; CHECK-NEXT:   %t = icmp eq i8* %x1, %foo
     93 ; CHECK-NEXT:   tail call void @objc_release(i8* %x1) [[NUW]], !clang.imprecise_release !0
     94 ; CHECK-NEXT:   ret i1 %t
     95 ; CHECK-NEXT: }
     96 define i1 @test4(i8* %newValue, i8* %foo) {
     97 entry:
     98   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
     99   %x1 = load i8** @x, align 8
    100   store i8* %newValue, i8** @x, align 8
    101   %t = icmp eq i8* %x1, %foo
    102   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
    103   ret i1 %t
    104 }
    105 
    106 ; Do form an objc_storeStrong here, because the use is before the store.
    107 
    108 ; CHECK: define i1 @test5(i8* %newValue, i8* %foo) {
    109 ; CHECK: %t = icmp eq i8* %x1, %foo
    110 ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]]
    111 ; CHECK: }
    112 define i1 @test5(i8* %newValue, i8* %foo) {
    113 entry:
    114   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
    115   %x1 = load i8** @x, align 8
    116   %t = icmp eq i8* %x1, %foo
    117   store i8* %newValue, i8** @x, align 8
    118   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
    119   ret i1 %t
    120 }
    121 
    122 ; Like test5, but the release is before the store.
    123 
    124 ; CHECK: define i1 @test6(i8* %newValue, i8* %foo) {
    125 ; CHECK: %t = icmp eq i8* %x1, %foo
    126 ; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %newValue) [[NUW]]
    127 ; CHECK: }
    128 define i1 @test6(i8* %newValue, i8* %foo) {
    129 entry:
    130   %x0 = tail call i8* @objc_retain(i8* %newValue) nounwind
    131   %x1 = load i8** @x, align 8
    132   tail call void @objc_release(i8* %x1) nounwind, !clang.imprecise_release !0
    133   %t = icmp eq i8* %x1, %foo
    134   store i8* %newValue, i8** @x, align 8
    135   ret i1 %t
    136 }
    137 
    138 ; Like test0, but there's no store, so don't form an objc_storeStrong.
    139 
    140 ;      CHECK-LABEL: define void @test7(
    141 ; CHECK-NEXT: entry:
    142 ; CHECK-NEXT:   %0 = tail call i8* @objc_retain(i8* %p) [[NUW]]
    143 ; CHECK-NEXT:   %tmp = load i8** @x, align 8
    144 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) [[NUW]]
    145 ; CHECK-NEXT:   ret void
    146 ; CHECK-NEXT: }
    147 define void @test7(i8* %p) {
    148 entry:
    149   %0 = tail call i8* @objc_retain(i8* %p) nounwind
    150   %tmp = load i8** @x, align 8
    151   tail call void @objc_release(i8* %tmp) nounwind
    152   ret void
    153 }
    154 
    155 ; Like test0, but there's no retain, so don't form an objc_storeStrong.
    156 
    157 ;      CHECK-LABEL: define void @test8(
    158 ; CHECK-NEXT: entry:
    159 ; CHECK-NEXT:   %tmp = load i8** @x, align 8
    160 ; CHECK-NEXT:   store i8* %p, i8** @x, align 8
    161 ; CHECK-NEXT:   tail call void @objc_release(i8* %tmp) [[NUW]]
    162 ; CHECK-NEXT:   ret void
    163 ; CHECK-NEXT: }
    164 define void @test8(i8* %p) {
    165 entry:
    166   %tmp = load i8** @x, align 8
    167   store i8* %p, i8** @x, align 8
    168   tail call void @objc_release(i8* %tmp) nounwind
    169   ret void
    170 }
    171 
    172 !0 = metadata !{}
    173 
    174 ; CHECK: attributes [[NUW]] = { nounwind }
    175