| // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -disable-sil-perf-optzns -O -Xllvm -swiftmergefunc-threshold=0 -emit-ir %s | %FileCheck %s |
| |
| // Check that IRGen lowers non-atomic reference counting instructions to |
| // proper runtime calls. |
| // Check that LLVM passes combine multiple retains/releases into |
| // retain_n/release_n and invoke a proper runtime function. Non-atomic runtime |
| // functions should be called only if all combined reference-counting |
| // instructions are non-atomic. |
| // |
| // Take into account that on Linux unknown_retain/unknown_release are not supported |
| // and native retain/release runtime functions are used instead. |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| public class C { |
| deinit |
| init() |
| } |
| |
| public protocol P : class { |
| } |
| |
| // foo(C) -> C |
| sil [noinline] @_TF28nonatomic_reference_counting3fooFCS_1CS0_ : $@convention(thin) (@owned C) -> @owned C { |
| bb0(%0 : $C): |
| return %0 : $C |
| } |
| |
| sil @doSomething : $@convention(thin) () -> () |
| |
| // CHECK-LABEL: define {{.*}}@test_strong_nonatomic_rr |
| // CHECK: call {{.*}}@swift_nonatomic_retain |
| // CHECK: call {{.*}}@swift_nonatomic_release |
| // CHECK: ret |
| sil @test_strong_nonatomic_rr: $@convention(thin) () -> @owned C { |
| bb0: |
| %1 = alloc_ref $C |
| strong_retain [nonatomic] %1 : $C |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release [nonatomic] %1 : $C |
| return %1 : $C |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_unknown_nonatomic_rr |
| // CHECK: call {{.*}}@{{(swift_nonatomic_unknownObjectRetain|swift_nonatomic_retain)}} |
| // CHECK: call {{.*}}@{{(swift_nonatomic_unknownObjectRelease|swift_nonatomic_release)}} |
| // CHECK: ret |
| sil @test_unknown_nonatomic_rr: $@convention(thin) <T where T : P> (@owned T) -> () { |
| bb0(%0 : $T): |
| strong_retain [nonatomic] %0 : $T |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release [nonatomic] %0 : $T |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_strong_nonatomic_rr_n |
| // CHECK: call {{.*}}@swift_nonatomic_retain_n |
| // CHECK: call {{.*}}@swift_nonatomic_release_n |
| // CHECK: ret |
| sil @test_strong_nonatomic_rr_n: $@convention(thin) () -> @owned C { |
| bb0: |
| %1 = alloc_ref $C |
| strong_retain [nonatomic] %1 : $C |
| strong_retain [nonatomic] %1 : $C |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release [nonatomic] %1 : $C |
| strong_release [nonatomic] %1 : $C |
| return %1 : $C |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_strong_mixed_rr_n |
| // CHECK: call {{.*}}@swift_retain_n |
| // CHECK: call {{.*}}@swift_release_n |
| // CHECK: ret |
| sil @test_strong_mixed_rr_n: $@convention(thin) () -> @owned C { |
| bb0: |
| %1 = alloc_ref $C |
| strong_retain [nonatomic] %1 : $C |
| strong_retain %1 : $C |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release %1 : $C |
| strong_release [nonatomic] %1 : $C |
| return %1 : $C |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_unknown_nonatomic_rr_n |
| // CHECK: call {{.*}}@{{(swift_nonatomic_unknownObjectRetain_n|swift_nonatomic_retain_n)}} |
| // CHECK: call {{.*}}@{{(swift_nonatomic_unknownObjectRelease_n|swift_nonatomic_release_n)}} |
| // CHECK: ret |
| sil @test_unknown_nonatomic_rr_n: $@convention(thin) <T where T : P> (@owned T) -> () { |
| bb0(%0 : $T): |
| strong_retain [nonatomic] %0 : $T |
| strong_retain [nonatomic] %0 : $T |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release [nonatomic] %0 : $T |
| strong_release [nonatomic] %0 : $T |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_unknown_mixed_rr_n |
| // CHECK: call {{.*}}@{{(swift_unknownObjectRetain_n|swift_retain_n)}} |
| // CHECK: call {{.*}}@{{(swift_unknownObjectRelease_n|swift_release_n)}} |
| // CHECK: ret |
| sil @test_unknown_mixed_rr_n: $@convention(thin) <T where T : P> (@owned T) -> () { |
| bb0(%0 : $T): |
| strong_retain [nonatomic] %0 : $T |
| strong_retain %0 : $T |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release %0 : $T |
| strong_release [nonatomic] %0 : $T |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| sil @test_unowned_nonatomic_rr: $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_ref $C |
| %1 = ref_to_unowned %0 : $C to $@sil_unowned C |
| unowned_retain [nonatomic] %1 : $@sil_unowned C |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| unowned_release [nonatomic] %1 : $@sil_unowned C |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_bridged_nonatomic_rr |
| // CHECK: call {{.*}}@swift_nonatomic_bridgeObjectRetain |
| // CHECK: call {{.*}}@swift_nonatomic_bridgeObjectRelease |
| // CHECK: ret |
| sil @test_bridged_nonatomic_rr: $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_ref $C |
| %1 = integer_literal $Builtin.Word, 0 |
| %2 = ref_to_bridge_object %0 : $C, %1 : $Builtin.Word |
| strong_retain [nonatomic] %2 : $Builtin.BridgeObject |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| strong_release [nonatomic] %2 : $Builtin.BridgeObject |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_bridged_nonatomic_rr_n |
| // CHECK: call {{.*}}@swift_nonatomic_bridgeObjectRetain_n |
| // CHECK: call {{.*}}@swift_nonatomic_bridgeObjectRelease_n |
| // CHECK: ret |
| sil @test_bridged_nonatomic_rr_n: $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_ref $C |
| %1 = integer_literal $Builtin.Word, 0 |
| %2 = ref_to_bridge_object %0 : $C, %1 : $Builtin.Word |
| strong_retain [nonatomic] %2 : $Builtin.BridgeObject |
| strong_retain [nonatomic] %2 : $Builtin.BridgeObject |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| //%f = function_ref @_TF28nonatomic_reference_counting3fooFCS_1CS0_ : $@convention(thin) (@owned C) -> @owned C |
| //%r = apply %f (%0) : $@convention(thin) (@owned C) -> @owned C |
| strong_release [nonatomic] %2 : $Builtin.BridgeObject |
| strong_release [nonatomic] %2 : $Builtin.BridgeObject |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_bridged_mixed_rr_n |
| // CHECK: call {{.*}}@swift_bridgeObjectRetain_n |
| // CHECK: call {{.*}}@swift_bridgeObjectRelease_n |
| // CHECK: ret |
| sil @test_bridged_mixed_rr_n: $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_ref $C |
| %1 = integer_literal $Builtin.Word, 0 |
| %2 = ref_to_bridge_object %0 : $C, %1 : $Builtin.Word |
| strong_retain [nonatomic] %2 : $Builtin.BridgeObject |
| strong_retain %2 : $Builtin.BridgeObject |
| %f = function_ref @doSomething : $@convention(thin) () -> () |
| %r = apply %f () : $@convention(thin) () -> () |
| //%f = function_ref @_TF28nonatomic_reference_counting3fooFCS_1CS0_ : $@convention(thin) (@owned C) -> @owned C |
| //%r = apply %f (%0) : $@convention(thin) (@owned C) -> @owned C |
| strong_release %2 : $Builtin.BridgeObject |
| strong_release [nonatomic] %2 : $Builtin.BridgeObject |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // C.__deallocating_deinit |
| sil @_TFC28nonatomic_reference_counting1CD : $@convention(method) (@owned C) -> () { |
| bb0(%0 : $C): |
| dealloc_ref %0 : $C |
| %4 = tuple () |
| return %4 : $() |
| } |
| |
| sil_vtable C { |
| #C.deinit!deallocator.1: @_TFC28nonatomic_reference_counting1CD // C.__deallocating_deinit |
| } |
| |