brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.5 KiB · 945811e Raw
280 lines · plain
1; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s2 3target datalayout = "e-p:64:64:64"4 5declare ptr @llvm.objc.retain(ptr)6declare void @llvm.objc.release(ptr)7declare void @use_pointer(ptr)8 9@x = external global ptr10 11; CHECK-LABEL: define void @test0(12; CHECK: entry:13; CHECK-NEXT: tail call void @llvm.objc.storeStrong(ptr @x, ptr %p) [[NUW:#[0-9]+]]14; CHECK-NEXT: ret void15; CHECK-NEXT: }16define void @test0(ptr %p) {17entry:18  %0 = tail call ptr @llvm.objc.retain(ptr %p) nounwind19  %tmp = load ptr, ptr @x, align 820  store ptr %0, ptr @x, align 821  tail call void @llvm.objc.release(ptr %tmp) nounwind22  ret void23}24 25; Don't do this if the load is volatile.26 27; CHECK-LABEL: define void @test1(ptr %p) {28; CHECK-NEXT: entry:29; CHECK-NEXT:   %0 = tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]30; CHECK-NEXT:   %tmp = load volatile ptr, ptr @x, align 831; CHECK-NEXT:   store ptr %0, ptr @x, align 832; CHECK-NEXT:   tail call void @llvm.objc.release(ptr %tmp) [[NUW]]33; CHECK-NEXT:   ret void34; CHECK-NEXT: }35define void @test1(ptr %p) {36entry:37  %0 = tail call ptr @llvm.objc.retain(ptr %p) nounwind38  %tmp = load volatile ptr, ptr @x, align 839  store ptr %0, ptr @x, align 840  tail call void @llvm.objc.release(ptr %tmp) nounwind41  ret void42}43 44; Don't do this if the store is volatile.45 46; CHECK-LABEL: define void @test2(ptr %p) {47; CHECK-NEXT: entry:48; CHECK-NEXT:   %0 = tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]49; CHECK-NEXT:   %tmp = load ptr, ptr @x, align 850; CHECK-NEXT:   store volatile ptr %0, ptr @x, align 851; CHECK-NEXT:   tail call void @llvm.objc.release(ptr %tmp) [[NUW]]52; CHECK-NEXT:   ret void53; CHECK-NEXT: }54define void @test2(ptr %p) {55entry:56  %0 = tail call ptr @llvm.objc.retain(ptr %p) nounwind57  %tmp = load ptr, ptr @x, align 858  store volatile ptr %0, ptr @x, align 859  tail call void @llvm.objc.release(ptr %tmp) nounwind60  ret void61}62 63; Don't do this if there's a use of the old pointer value between the store64; and the release.65 66; CHECK-LABEL: define void @test3(ptr %newValue) {67; CHECK-NEXT:  entry:68; CHECK-NEXT:    %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) [[NUW]]69; CHECK-NEXT:    %x1 = load ptr, ptr @x, align 870; CHECK-NEXT:    store ptr %x0, ptr @x, align 871; CHECK-NEXT:    tail call void @use_pointer(ptr %x1), !clang.arc.no_objc_arc_exceptions !072; CHECK-NEXT:    tail call void @llvm.objc.release(ptr %x1) [[NUW]], !clang.imprecise_release !073; CHECK-NEXT:    ret void74; CHECK-NEXT:  }75define void @test3(ptr %newValue) {76entry:77  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind78  %x1 = load ptr, ptr @x, align 879  store ptr %newValue, ptr @x, align 880  tail call void @use_pointer(ptr %x1), !clang.arc.no_objc_arc_exceptions !081  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !082  ret void83}84 85; Like test3, but with an icmp use instead of a call, for good measure.86 87; CHECK-LABEL:  define i1 @test4(ptr %newValue, ptr %foo) {88; CHECK-NEXT:   entry:89; CHECK-NEXT:     %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) [[NUW]]90; CHECK-NEXT:     %x1 = load ptr, ptr @x, align 891; CHECK-NEXT:     store ptr %x0, ptr @x, align 892; CHECK-NEXT:     %t = icmp eq ptr %x1, %foo93; CHECK-NEXT:     tail call void @llvm.objc.release(ptr %x1) [[NUW]], !clang.imprecise_release !094; CHECK-NEXT:     ret i1 %t95; CHECK-NEXT:   }96define i1 @test4(ptr %newValue, ptr %foo) {97entry:98  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind99  %x1 = load ptr, ptr @x, align 8100  store ptr %newValue, ptr @x, align 8101  %t = icmp eq ptr %x1, %foo102  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !0103  ret i1 %t104}105 106; Do form an llvm.objc.storeStrong here, because the use is before the store.107 108; CHECK-LABEL: define i1 @test5(ptr %newValue, ptr %foo) {109; CHECK: %t = icmp eq ptr %x1, %foo110; CHECK: tail call void @llvm.objc.storeStrong(ptr @x, ptr %newValue) [[NUW]]111; CHECK: }112define i1 @test5(ptr %newValue, ptr %foo) {113entry:114  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind115  %x1 = load ptr, ptr @x, align 8116  %t = icmp eq ptr %x1, %foo117  store ptr %newValue, ptr @x, align 8118  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !0119  ret i1 %t120}121 122; Like test5, but the release is before the store.123 124; CHECK-LABEL: define i1 @test6(ptr %newValue, ptr %foo) {125; CHECK: %t = icmp eq ptr %x1, %foo126; CHECK: tail call void @llvm.objc.storeStrong(ptr @x, ptr %newValue) [[NUW]]127; CHECK: }128define i1 @test6(ptr %newValue, ptr %foo) {129entry:130  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind131  %x1 = load ptr, ptr @x, align 8132  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !0133  %t = icmp eq ptr %x1, %foo134  store ptr %newValue, ptr @x, align 8135  ret i1 %t136}137 138; Like test0, but there's no store, so don't form an llvm.objc.storeStrong.139 140; CHECK-LABEL: define void @test7(141; CHECK-NEXT: entry:142; CHECK-NEXT:   %0 = tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]143; CHECK-NEXT:   %tmp = load ptr, ptr @x, align 8144; CHECK-NEXT:   tail call void @llvm.objc.release(ptr %tmp) [[NUW]]145; CHECK-NEXT:   ret void146; CHECK-NEXT: }147define void @test7(ptr %p) {148entry:149  %0 = tail call ptr @llvm.objc.retain(ptr %p) nounwind150  %tmp = load ptr, ptr @x, align 8151  tail call void @llvm.objc.release(ptr %tmp) nounwind152  ret void153}154 155; Like test0, but there's no retain, so don't form an llvm.objc.storeStrong.156 157; CHECK-LABEL: define void @test8(158; CHECK-NEXT: entry:159; CHECK-NEXT:   %tmp = load ptr, ptr @x, align 8160; CHECK-NEXT:   store ptr %p, ptr @x, align 8161; CHECK-NEXT:   tail call void @llvm.objc.release(ptr %tmp) [[NUW]]162; CHECK-NEXT:   ret void163; CHECK-NEXT: }164define void @test8(ptr %p) {165entry:166  %tmp = load ptr, ptr @x, align 8167  store ptr %p, ptr @x, align 8168  tail call void @llvm.objc.release(ptr %tmp) nounwind169  ret void170}171 172; Make sure that we properly handle release that *may* release our new173; value in between the retain and the store. We need to be sure that174; this we can safely move the retain to the store. This specific test175; makes sure that we properly handled a release of an unrelated176; pointer.177;178; CHECK-LABEL: define i1 @test9(ptr %newValue, ptr %foo, ptr %unrelated_ptr) {179; CHECK-NOT: llvm.objc.storeStrong180define i1 @test9(ptr %newValue, ptr %foo, ptr %unrelated_ptr) {181entry:182  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind183  tail call void @llvm.objc.release(ptr %unrelated_ptr) nounwind, !clang.imprecise_release !0184  %x1 = load ptr, ptr @x, align 8185  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !0186  %t = icmp eq ptr %x1, %foo187  store ptr %newValue, ptr @x, align 8188  ret i1 %t189}190 191; Make sure that we don't perform the optimization when we just have a call.192;193; CHECK-LABEL: define i1 @test10(ptr %newValue, ptr %foo, ptr %unrelated_ptr) {194; CHECK-NOT: llvm.objc.storeStrong195define i1 @test10(ptr %newValue, ptr %foo, ptr %unrelated_ptr) {196entry:197  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind198  call void @use_pointer(ptr %unrelated_ptr)199  %x1 = load ptr, ptr @x, align 8200  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !0201  %t = icmp eq ptr %x1, %foo202  store ptr %newValue, ptr @x, align 8203  ret i1 %t204}205 206; Make sure we form the store strong if the use in between the retain207; and the store does not touch reference counts.208; CHECK-LABEL: define i1 @test11(ptr %newValue, ptr %foo, ptr %unrelated_ptr) {209; CHECK: llvm.objc.storeStrong210define i1 @test11(ptr %newValue, ptr %foo, ptr %unrelated_ptr) {211entry:212  %x0 = tail call ptr @llvm.objc.retain(ptr %newValue) nounwind213  %t = icmp eq ptr %newValue, %foo214  %x1 = load ptr, ptr @x, align 8215  tail call void @llvm.objc.release(ptr %x1) nounwind, !clang.imprecise_release !0216  store ptr %newValue, ptr @x, align 8217  ret i1 %t218}219 220; Make sure that we form the store strong even if there are bitcasts on221; the pointers.222; CHECK-LABEL: define void @test12(223; CHECK: entry:224; CHECK-NEXT: %p16 = bitcast ptr @x to ptr225; CHECK-NEXT: %tmp16 = load ptr, ptr %p16, align 8226; CHECK-NEXT: %tmp8 = bitcast ptr %tmp16 to ptr227; CHECK-NEXT: %p32 = bitcast ptr @x to ptr228; CHECK-NEXT: %v32 = bitcast ptr %p to ptr229; CHECK-NEXT: tail call void @llvm.objc.storeStrong(ptr %p16, ptr %p)230; CHECK-NEXT: ret void231; CHECK-NEXT: }232define void @test12(ptr %p) {233entry:234  %retain = tail call ptr @llvm.objc.retain(ptr %p) nounwind235  %p16 = bitcast ptr @x to ptr236  %tmp16 = load ptr, ptr %p16, align 8237  %tmp8 = bitcast ptr %tmp16 to ptr238  %p32 = bitcast ptr @x to ptr239  %v32 = bitcast ptr %retain to ptr240  store ptr %v32, ptr %p32, align 8241  tail call void @llvm.objc.release(ptr %tmp8) nounwind242  ret void243}244 245; This used to crash.246; CHECK-LABEL: define ptr @test13(247; CHECK: tail call void @llvm.objc.storeStrong(ptr %{{.*}}, ptr %[[NEW:.*]])248; CHECK-NEXT: ret ptr %[[NEW]]249 250define ptr @test13(ptr %a0, ptr %a1, ptr %addr, ptr %new) {251  %old = load ptr, ptr %addr, align 8252  call void @llvm.objc.release(ptr %old)253  %retained = call ptr @llvm.objc.retain(ptr %new)254  store ptr %retained, ptr %addr, align 8255  ret ptr %retained256}257 258; Cannot form a storeStrong call because it's unsafe to move the release call to259; the store.260 261; CHECK-LABEL: define void @test14(262; CHECK: %[[V0:.*]] = load ptr, ptr %a263; CHECK: %[[V1:.*]] = call ptr @llvm.objc.retain(ptr %p)264; CHECK: store ptr %[[V1]], ptr %a265; CHECK: %[[V2:.*]] = call ptr @llvm.objc.retain(ptr %[[V0]])266; CHECK: call void @llvm.objc.release(ptr %[[V2]])267 268define void @test14(ptr %a, ptr %p) {269  %v0 = load ptr, ptr %a, align 8270  %v1 = call ptr @llvm.objc.retain(ptr %p)271  store ptr %p, ptr %a, align 8272  %v2  = call ptr @llvm.objc.retain(ptr %v0)273  call void @llvm.objc.release(ptr %v0)274  ret void275}276 277!0 = !{}278 279; CHECK: attributes [[NUW]] = { nounwind }280