blob: 4a03ce1eabcbc5d9fe54f97b1a28e1201cb3498e [file] [log] [blame]
// 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 : $()
}