| // RUN: %target-sil-opt -wmo -enable-sil-verify-all -emit-sorted-sil %s -enable-existential-specializer -existential-specializer -inline -sil-combine -generic-specializer -devirtualizer 2>&1 | %FileCheck %s |
| |
| // This file tests existential specializer transformation followed by concrete type propagation and generic specialization leading to a devirtualization of a witness method call. |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| protocol RP { |
| func getThres() -> Int32 |
| } |
| |
| class RC : RP { |
| @inline(never) func getThres() -> Int32 |
| } |
| |
| sil hidden [noinline] @$s6test0_2RCC8getThress5Int32VyF : $@convention(method) (@guaranteed RC) -> Int32 { |
| bb0(%0 : $RC): |
| %1 = integer_literal $Builtin.Int32, 10 |
| %2 = struct $Int32 (%1 : $Builtin.Int32) |
| return %2 : $Int32 |
| } |
| |
| sil private [transparent] [thunk] @$s6test0_2RCCAA2RPA2aDP8getThress5Int32VyFTW : $@convention(witness_method: RP) (@in_guaranteed RC) -> Int32 { |
| bb0(%0 : $*RC): |
| %1 = load %0 : $*RC |
| %2 = class_method %1 : $RC, #RC.getThres!1 : (RC) -> () -> Int32, $@convention(method) (@guaranteed RC) -> Int32 |
| %3 = apply %2(%1) : $@convention(method) (@guaranteed RC) -> Int32 |
| return %3 : $Int32 |
| } |
| |
| sil_vtable RC { |
| #RC.getThres!1: (RC) -> () -> Int32 : @$s6test0_2RCC8getThress5Int32VyF |
| } |
| |
| sil_witness_table hidden RC: RP module simple { |
| method #RP.getThres!1: <Self where Self : RP> (Self) -> () -> Int32 : @$s6test0_2RCCAA2RPA2aDP8getThress5Int32VyFTW |
| } |
| |
| // Note: The function_ref of "function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptFTf4ne_n4main2RCC_Tg5 : $@convention(thin) (Int32, @guaranteed RC) -> Bool" in the transformed code was originally a "function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptF : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool" taking an existential parameter and has been generic specialized after existential specialization. |
| // CHECK-LABEL: sil hidden [noinline] @$s6test0_12find_wrapperSbyF : $@convention(thin) () -> Bool { |
| // CHECK: bb0: |
| // CHECK: alloc_ref |
| // CHECK: integer_literal |
| // CHECK: struct |
| // CHECK: alloc_stack |
| // CHECK: store |
| // CHECK: strong_retain |
| // CHECK: function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptFTf4ne_n4main2RCC_Tg5 : $@convention(thin) (Int32, @guaranteed RC) -> Bool |
| // CHECK: load |
| // CHECK: apply |
| // CHECK: destroy_addr |
| // CHECK: dealloc_stack |
| // CHECK: strong_release |
| // CHECK: return |
| // CHECK-LABEL: } // end sil function '$s6test0_12find_wrapperSbyF' |
| sil hidden [noinline] @$s6test0_12find_wrapperSbyF : $@convention(thin) () -> Bool { |
| bb0: |
| %0 = alloc_ref $RC |
| %3 = integer_literal $Builtin.Int32, 0 |
| %4 = struct $Int32 (%3 : $Builtin.Int32) |
| %5 = alloc_stack $RP |
| %6 = init_existential_addr %5 : $*RP, $RC |
| store %0 to %6 : $*RC |
| %8 = function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptF : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool |
| strong_retain %0 : $RC |
| %10 = apply %8(%4, %5) : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool |
| destroy_addr %5 : $*RP |
| dealloc_stack %5 : $*RP |
| strong_release %0 : $RC |
| return %10 : $Bool |
| } |
| |
| // Note 1: The function_ref of "function_ref @$s6test0_2RCC8getThress5Int32VyF : $@convention(method) (@guaranteed RC) -> Int32" in the transformed code was originally a witness method "witness_method $@opened("7AE0C0CA-28D3-11E9-B1D4-F21898973DF0") RP, #RP.getThres!1 : <Self where Self : RP> (Self) -> () -> Int32, %4 : $*@opened("7AE0C0CA-28D3-11E9-B1D4-F21898973DF0") RP : $@convention(witness_method: RP) <τ_0_0 where τ_0_0 : RP> (@in_guaranteed τ_0_0) -> Int32" and has been devirtualized after existential specialization. |
| // Note 2: The function_ref of "function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptFTf4ne_n4main2RCC_Tg5 : $@convention(thin) (Int32, @guaranteed RC) -> Bool" in the transformed code was originally a "function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptF : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool" taking an existential parameter and has been generic specialized after existential specialization. |
| // CHECK-LABEL: sil shared [noinline] @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptFTf4ne_n4main2RCC_Tg5 : $@convention(thin) (Int32, @guaranteed RC) -> Bool { |
| // CHECK: bb0 |
| // CHECK: alloc_stack |
| // CHECK: store |
| // CHECK: alloc_stack |
| // CHECK: init_existential_addr |
| // CHECK: copy_addr |
| // CHECK: open_existential_addr |
| // CHECK: unchecked_addr_cast |
| // CHECK: load |
| // CHECK: function_ref @$s6test0_2RCC8getThress5Int32VyF : $@convention(method) (@guaranteed RC) -> Int32 |
| // CHECK: apply |
| // CHECK: struct_extract |
| // CHECK: struct_extract |
| // CHECK: builtin |
| // CHECK: cond_br |
| // CHECK: bb1: |
| // CHECK: integer_literal |
| // CHECK: struct |
| // CHECK: br |
| // CHECK: bb2: |
| // CHECK: integer_literal |
| // CHECK: integer_literal |
| // CHECK: builtin |
| // CHECK: tuple_extract |
| // CHECK: struct |
| // CHECK: function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptFTf4ne_n4main2RCC_Tg5 : $@convention(thin) (Int32, @guaranteed RC) -> Bool |
| // CHECK: load |
| // CHECK: apply |
| // CHECK: br |
| // CHECK: bb3 |
| // CHECK: dealloc_stack |
| // CHECK: dealloc_stack |
| // CHECK: return |
| // CHECK-LABEL: } // end sil function '$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptFTf4ne_n4main2RCC_Tg5' |
| sil hidden [noinline] @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptF : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool { |
| bb0(%0 : $Int32, %1 : $*RP): |
| %4 = open_existential_addr immutable_access %1 : $*RP to $*@opened("7AE0C0CA-28D3-11E9-B1D4-F21898973DF0") RP |
| %5 = witness_method $@opened("7AE0C0CA-28D3-11E9-B1D4-F21898973DF0") RP, #RP.getThres!1 : <Self where Self : RP> (Self) -> () -> Int32, %4 : $*@opened("7AE0C0CA-28D3-11E9-B1D4-F21898973DF0") RP : $@convention(witness_method: RP) <τ_0_0 where τ_0_0 : RP> (@in_guaranteed τ_0_0) -> Int32 |
| %6 = apply %5<@opened("7AE0C0CA-28D3-11E9-B1D4-F21898973DF0") RP>(%4) : $@convention(witness_method: RP) <τ_0_0 where τ_0_0 : RP> (@in_guaranteed τ_0_0) -> Int32 |
| %7 = struct_extract %0 : $Int32, #Int32._value |
| %8 = struct_extract %6 : $Int32, #Int32._value |
| %9 = builtin "cmp_slt_Int32"(%7 : $Builtin.Int32, %8 : $Builtin.Int32) : $Builtin.Int1 |
| cond_br %9, bb2, bb1 |
| |
| bb1: |
| %11 = integer_literal $Builtin.Int1, -1 |
| %12 = struct $Bool (%11 : $Builtin.Int1) |
| br bb3(%12 : $Bool) |
| |
| bb2: |
| %14 = integer_literal $Builtin.Int32, 1 |
| %15 = integer_literal $Builtin.Int1, -1 |
| %16 = builtin "sadd_with_overflow_Int32"(%7 : $Builtin.Int32, %14 : $Builtin.Int32, %15 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) |
| %17 = tuple_extract %16 : $(Builtin.Int32, Builtin.Int1), 0 |
| %18 = struct $Int32 (%17 : $Builtin.Int32) |
| %19 = function_ref @$s6test0_4find5count4Obj1Sbs5Int32V_AA2RP_ptF : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool |
| %20 = apply %19(%18, %1) : $@convention(thin) (Int32, @in_guaranteed RP) -> Bool |
| br bb3(%20 : $Bool) |
| |
| bb3(%22 : $Bool): |
| return %22 : $Bool |
| } |
| |
| // <rdar://problem/49336444> SILCombine infinite loop. |
| // |
| // Test a apply argument from an init_existential with a sole |
| // conforming type. We currently bail on rewriting the apply because |
| // it returns the same substituted type. Avoid infinitely iterating in |
| // SILCombine due to repeatedly creating an destroying the same cast. |
| public protocol BaseProtocol { |
| func testProtocolMethod() -> Self |
| } |
| extension BaseProtocol { |
| func testProtocolMethod() -> Self { |
| return self |
| } |
| } |
| |
| protocol SubProtocol : BaseProtocol {} |
| |
| final class ClassImpl : SubProtocol {} |
| |
| extension ClassImpl { |
| final func testProtocolMethod() -> ClassImpl |
| } |
| |
| sil @$s6testProtocolMethod : $@convention(method) <τ_0_0 where τ_0_0 : BaseProtocol> (@in_guaranteed τ_0_0) -> @out τ_0_0 |
| |
| // Verify that the optimization was not performance and that we don't hang as a result. |
| // CHECK-LABEL: sil hidden @$s6test1_ConcreteInitExistential : $@convention(method) (@in SubProtocol) -> () { |
| // CHECK: [[E:%.*]] = init_existential_addr %{{.*}} : $*SubProtocol, $@opened("{{.*}}") SubProtocol |
| // CHECK: apply %{{.*}}<@opened("{{.*}}") SubProtocol>([[E]], %{{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : BaseProtocol> (@in_guaranteed τ_0_0) -> @out τ_0_0 |
| // CHECK-LABEL: } // end sil function '$s6test1_ConcreteInitExistential' |
| sil hidden @$s6test1_ConcreteInitExistential : $@convention(method) (@in SubProtocol) -> () { |
| bb0(%0 : $*SubProtocol): |
| %10 = open_existential_addr immutable_access %0 : $*SubProtocol to $*@opened("CA90348E-5376-11E9-8C51-ACDE48001122") SubProtocol |
| %11 = alloc_stack $SubProtocol |
| %15 = function_ref @$s6testProtocolMethod : $@convention(method) <τ_0_0 where τ_0_0 : BaseProtocol> (@in_guaranteed τ_0_0) -> @out τ_0_0 |
| %16 = init_existential_addr %11 : $*SubProtocol, $@opened("CA90348E-5376-11E9-8C51-ACDE48001122") SubProtocol |
| %17 = apply %15<@opened("CA90348E-5376-11E9-8C51-ACDE48001122") SubProtocol>(%16, %10) : $@convention(method) <τ_0_0 where τ_0_0 : BaseProtocol> (@in_guaranteed τ_0_0) -> @out τ_0_0 |
| dealloc_stack %11 : $*SubProtocol |
| %80 = tuple () |
| return %80 : $() |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Test an existential argument that is consumed and explicitly destroyed. |
| // <rdar://problem/50595630> Multiple leaks detected |
| //===----------------------------------------------------------------------===// |
| public protocol P {} |
| |
| public struct S : P { |
| init() |
| |
| var o: AnyObject // nontrivial to check ownership conventions |
| } |
| |
| // Check the thunk. |
| // CHECK-LABEL: sil hidden [signature_optimized_thunk] [always_inline] @$s6test2_6storePyyAA1P_p_AaC_pztF : $@convention(thin) (@in P, @inout P) -> () { |
| // CHECK: bb0(%0 : $*P, %1 : $*P): |
| // CHECK: [[F:%.*]] = function_ref @$s6test2_6storePyyAA1P_p_AaC_pztFTf4en_n : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @inout P) -> () |
| // CHECK: [[ADR:%.*]] = open_existential_addr mutable_access %0 : $*P to $*@opened([[TY:".*"]]) P |
| // CHECK: [[ALLOC:%.*]] = alloc_stack $@opened([[TY]]) P |
| // CHECK: copy_addr [[ADR]] to [initialization] [[ALLOC]] : $*@opened([[TY]]) P |
| // CHECK: apply [[F]]<@opened("{{.*}}") P>([[ALLOC]], %1) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @inout P) -> () |
| // CHECK: destroy_addr %0 : $*P |
| // CHECK: dealloc_stack [[ALLOC]] : $*@opened([[TY]]) P |
| // CHECK: return |
| // CHECK-LABEL: } // end sil function '$s6test2_6storePyyAA1P_p_AaC_pztF' |
| |
| |
| // Check the existential to generic specialization. |
| // CHECK-LABEL: sil shared [noinline] @$s6test2_6storePyyAA1P_p_AaC_pztFTf4en_n : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0, @inout P) -> () { |
| // CHECK: bb0(%0 : $*τ_0_0, %1 : $*P): |
| // CHECK: [[ALLOC:%.*]] = alloc_stack $P |
| // CHECK: [[IEA:%.*]] = init_existential_addr [[ALLOC]] : $*P, $τ_0_0 |
| // CHECK: copy_addr [take] %0 to [initialization] [[IEA]] : $*τ_0_0 |
| // CHECK-NOT: destroy |
| // CHECK: copy_addr [[ALLOC]] to [initialization] %1 : $*P |
| // CHECK-NOT: destroy |
| // CHECK: destroy_addr [[ALLOC]] : $*P |
| // CHECK-NOT: destroy |
| // CHECK-LABEL: } // end sil function '$s6test2_6storePyyAA1P_p_AaC_pztFTf4en_n' |
| |
| // Check the generic to concrete specialization. |
| // CHECK-LABEL: sil shared [noinline] @$s6test2_6storePyyAA1P_p_AaC_pztFTf4en_n4main1SV_Tg5 : $@convention(thin) (@owned S, @inout P) -> () { |
| // CHECK: bb0(%0 : $S, %1 : $*P): |
| // CHECK: [[ALLOCS:%.*]] = alloc_stack $S |
| // CHECK: [[ALLOCP:%.*]] = alloc_stack $P |
| // CHECK: [[IEA:%.*]] = init_existential_addr [[ALLOCP]] : $*P, $S |
| // CHECK: copy_addr [take] [[ALLOCS]] to [initialization] [[IEA]] : $*S |
| // CHECK-NOT: destroy |
| // CHECK: copy_addr [[ALLOCP]] to [initialization] %1 : $*P |
| // CHECK: destroy_addr [[ALLOCP]] : $*P |
| // CHECK: dealloc_stack [[ALLOCP]] |
| // CHECK: dealloc_stack [[ALLOCS]] |
| // CHECK-LABEL: } // end sil function '$s6test2_6storePyyAA1P_p_AaC_pztFTf4en_n4main1SV_Tg5' |
| sil hidden [noinline] @$s6test2_6storePyyAA1P_p_AaC_pztF : $@convention(thin) (@in P, @inout P) -> () { |
| bb0(%0 : $*P, %1 : $*P): |
| copy_addr %0 to [initialization] %1 : $*P |
| destroy_addr %0 : $*P |
| %5 = tuple () |
| return %5 : $() |
| } |
| |
| // CHECK-LABEL: sil @$s6test2_6storeS1s1qyAA1SV_AA1P_pztF : $@convention(thin) (S, @inout P) -> () { |
| // CHECK: bb0(%0 : $S, %1 : $*P): |
| // CHECK: [[ALLOCS1:%.*]] = alloc_stack $S |
| // CHECK: store %0 to [[ALLOCS1]] : $*S |
| // CHECK: [[ALLOCS2:%.*]] = alloc_stack $S |
| // CHECK: copy_addr [[ALLOCS1]] to [initialization] [[ALLOCS2]] : $*S |
| // CHECK: [[F:%.*]] = function_ref @$s6test2_6storePyyAA1P_p_AaC_pztFTf4en_n4main1SV_Tg5 : $@convention(thin) (@owned S, @inout P) -> () |
| // CHECK: [[S:%.*]] = load [[ALLOCS2]] : $*S |
| // CHECK: apply [[F]]([[S]], %1) : $@convention(thin) (@owned S, @inout P) -> () |
| // CHECK-NEXT: dealloc_stack [[ALLOCS2]] : $*S |
| // CHECK-NEXT: destroy_addr [[ALLOCS1]] : $*S |
| // CHECK-NEXT: dealloc_stack [[ALLOCS1]] : $*S |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| // CHECK-LABEL: } // end sil function '$s6test2_6storeS1s1qyAA1SV_AA1P_pztF' |
| sil @$s6test2_6storeS1s1qyAA1SV_AA1P_pztF : $@convention(thin) (S, @inout P) -> () { |
| bb0(%0 : $S, %1 : $*P): |
| %4 = alloc_stack $P |
| %5 = init_existential_addr %4 : $*P, $S |
| store %0 to %5 : $*S |
| %7 = function_ref @$s6test2_6storePyyAA1P_p_AaC_pztF : $@convention(thin) (@in P, @inout P) -> () |
| %8 = apply %7(%4, %1) : $@convention(thin) (@in P, @inout P) -> () |
| dealloc_stack %4 : $*P |
| %10 = tuple () |
| return %10 : $() |
| } |
| |
| sil_witness_table S: P module test {} |
| |
| //===----------------------------------------------------------------------===// |
| // Test an existential in_guaranteed argument. |
| //===----------------------------------------------------------------------===// |
| |
| // CHECK-LABEL: sil hidden [signature_optimized_thunk] [always_inline] @$s6test3_6storePyyAA1P_pz_AaC_pztF : $@convention(thin) (@in_guaranteed P, @inout P) -> () { |
| // CHECK: bb0(%0 : $*P, %1 : $*P): |
| // CHECK: [[F:%.*]] = function_ref @$s6test3_6storePyyAA1P_pz_AaC_pztFTf4en_n : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0, @inout P) -> () |
| // CHECK: [[ADR:%.*]] = open_existential_addr immutable_access %0 : $*P to $*@opened("{{.*}}") P |
| // CHECK: apply [[F]]<@opened("{{.*}}") P>([[ADR]], %1) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0, @inout P) -> () |
| // CHECK-LABEL: } // end sil function '$s6test3_6storePyyAA1P_pz_AaC_pztF' |
| |
| // The guaranteed concrete argument cannot be consumed. The |
| // existential created in the prolog must be destroyed before |
| // returing. |
| // |
| // CHECK-LABEL: sil shared @$s6test3_6storePyyAA1P_pz_AaC_pztFTf4en_n : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0, @inout P) -> () { |
| // CHECK: bb0(%0 : $*τ_0_0, %1 : $*P): |
| // CHECK: [[ALLOCP1:%.*]] = alloc_stack $P |
| // CHECK: [[ADR:%.*]] = init_existential_addr [[ALLOCP1]] : $*P, $τ_0_0 |
| // CHECK: copy_addr %0 to [initialization] [[ADR]] : $*τ_0_0 |
| // CHECK: [[ALLOCP2:%.*]] = alloc_stack $P |
| // CHECK: copy_addr [[ALLOCP1]] to [initialization] [[ALLOCP2]] : $*P |
| // CHECK: copy_addr [take] [[ALLOCP2]] to %1 : $*P |
| // CHECK: destroy_addr [[ALLOCP1]] : $*P |
| // CHECK: dealloc_stack [[ALLOCP1]] : $*P |
| // CHECK-LABEL: } // end sil function '$s6test3_6storePyyAA1P_pz_AaC_pztFTf4en_n' |
| sil hidden @$s6test3_6storePyyAA1P_pz_AaC_pztF : $@convention(thin) (@in_guaranteed P, @inout P) -> () { |
| bb0(%0 : $*P, %1 : $*P): |
| %5 = alloc_stack $P |
| copy_addr %0 to [initialization] %5 : $*P |
| copy_addr [take] %5 to %1 : $*P |
| dealloc_stack %5 : $*P |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| // CHECK-LABEL: sil shared @$s6test3_6storePyyAA1P_pz_AaC_pztFTf4en_n4main1SV_Tg5 : $@convention(thin) (@guaranteed S, @inout P) -> () { |
| // CHECK: bb0(%0 : $S, %1 : $*P): |
| // CHECK: [[ALLOC1:%.*]] = alloc_stack $S |
| // CHECK: store %0 to [[ALLOC1]] : $*S |
| // CHECK: [[ALLOC2:%.*]] = alloc_stack $P |
| // CHECK: [[ADR:%.*]] = init_existential_addr [[ALLOC2]] : $*P, $S |
| // CHECK: copy_addr [[ALLOC1]] to [initialization] [[ADR]] : $*S |
| // CHECK: [[ALLOC3:%.*]] = alloc_stack $P |
| // CHECK: copy_addr [[ALLOC2]] to [initialization] [[ALLOC3]] : $*P |
| // CHECK: copy_addr [take] [[ALLOC3]] to %1 : $*P |
| // CHECK: dealloc_stack [[ALLOC3]] : $*P |
| // CHECK: destroy_addr [[ALLOC2]] : $*P |
| // CHECK: dealloc_stack %4 : $*P |
| // CHECK: dealloc_stack %2 : $*S |
| // CHECK-LABEL: } // end sil function '$s6test3_6storePyyAA1P_pz_AaC_pztFTf4en_n4main1SV_Tg5' |
| sil hidden @$s6test3_6storeS1s1qyAA1SV_AA1P_pztF : $@convention(thin) (S, @inout P) -> () { |
| bb0(%0 : $S, %1 : $*P): |
| %4 = alloc_stack $P, var, name "sp" |
| %5 = init_existential_addr %4 : $*P, $S |
| store %0 to %5 : $*S |
| %9 = function_ref @$s6test3_6storePyyAA1P_pz_AaC_pztF : $@convention(thin) (@in_guaranteed P, @inout P) -> () |
| %10 = apply %9(%4, %1) : $@convention(thin) (@in_guaranteed P, @inout P) -> () |
| destroy_addr %4 : $*P |
| dealloc_stack %4 : $*P |
| %15 = tuple () |
| return %15 : $() |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Test an existential inout argument. |
| //===----------------------------------------------------------------------===// |
| |
| // The ExistentialSpecializer cannot specialize on an @inout argument |
| // CHECK-LABEL: sil hidden @$s6test4_6storePyyAA1P_pz_AaC_pztF : $@convention(thin) (@inout P, @inout P) -> () { |
| // CHECK: bb0(%0 : $*P, %1 : $*P): |
| // CHECK: [[ALLOC:%.*]] = alloc_stack $P |
| // CHECK: copy_addr %0 to [initialization] [[ALLOC]] : $*P |
| // CHECK: copy_addr [take] [[ALLOC]] to %1 : $*P |
| // CHECK: dealloc_stack [[ALLOC]] : $*P |
| // CHECK-LABEL: } // end sil function '$s6test4_6storePyyAA1P_pz_AaC_pztF' |
| sil hidden @$s6test4_6storePyyAA1P_pz_AaC_pztF : $@convention(thin) (@inout P, @inout P) -> () { |
| bb0(%0 : $*P, %1 : $*P): |
| %5 = alloc_stack $P |
| copy_addr %0 to [initialization] %5 : $*P |
| copy_addr [take] %5 to %1 : $*P |
| dealloc_stack %5 : $*P |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| // ...and there's currently no way to propagate the concrete value to the inout argument! |
| // CHECK-LABEL: sil hidden @$s6test4_6storeS1s1qyAA1SV_AA1P_pztF : $@convention(thin) (S, @inout P) -> () { |
| // CHECK: bb0(%0 : $S, %1 : $*P): |
| // CHECK: [[ALLOC:%.*]] = alloc_stack $P, var, name "sp" |
| // CHECK: [[ADR1:%.*]] = init_existential_addr [[ALLOC]] : $*P, $S |
| // CHECK: store %0 to [[ADR1]] : $*S |
| // CHECK: [[ALLOC2:%.*]] = alloc_stack $P |
| // CHECK: copy_addr %2 to [initialization] %5 : $*P |
| // CHECK: copy_addr [take] %5 to %1 : $*P |
| // CHECK: destroy_addr [[ALLOC]] : $*P |
| // CHECK: dealloc_stack [[ALLOC]] : $*P |
| // CHECK-LABEL: } // end sil function '$s6test4_6storeS1s1qyAA1SV_AA1P_pztF' |
| sil hidden @$s6test4_6storeS1s1qyAA1SV_AA1P_pztF : $@convention(thin) (S, @inout P) -> () { |
| bb0(%0 : $S, %1 : $*P): |
| %4 = alloc_stack $P, var, name "sp" |
| %5 = init_existential_addr %4 : $*P, $S |
| store %0 to %5 : $*S |
| %9 = function_ref @$s6test4_6storePyyAA1P_pz_AaC_pztF : $@convention(thin) (@inout P, @inout P) -> () |
| %10 = apply %9(%4, %1) : $@convention(thin) (@inout P, @inout P) -> () |
| destroy_addr %4 : $*P |
| dealloc_stack %4 : $*P |
| %15 = tuple () |
| return %15 : $() |
| } |
| |