blob: c6eba956487182c76a3c598877eaf2a0bd278023 [file] [log] [blame]
// RUN: %target-swift-frontend -O -sil-existential-specializer -Xllvm -sil-disable-pass=GenericSpecializer -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=SILCombine -emit-sil -sil-verify-all %s | %FileCheck %s
internal protocol SomeProtocol : class {
func foo() -> Int
}
internal class SomeClass: SomeProtocol {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
}
@inline(never) internal func wrap_foo_cp(a:SomeProtocol ) -> Int{
return a.foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform2cpyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: init_existential_ref
// CHECK: debug_value
// CHECK: function_ref @$s21existential_transform11wrap_foo_cp1aSiAA12SomeProtocol_p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SomeProtocol> (@guaranteed τ_0_0) -> Int
// CHECK: open_existential_ref
// CHECK: apply
// CHECK: set_deallocating
// CHECK: debug_value
// CHECK: debug_value
// CHECK: dealloc_ref
// CHECK: dealloc_ref
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform2cpyyF'
@inline(never) func cp() {
let magic1:SomeProtocol = SomeClass()
let _ = wrap_foo_cp(a:magic1)
}
/// Non Class Protocol
internal protocol SomeNoClassProtocol {
func foo() -> Int
}
internal class SomeNoClass: SomeNoClassProtocol {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
}
@inline(never) internal func wrap_foo_ncp(a:SomeNoClassProtocol) -> Int{
return a.foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform3ncpyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_stack
// CHECK: alloc_ref $SomeNoClass
// CHECK: debug_value
// CHECK: init_existential_addr
// CHECK: store
// CHECK: function_ref @$s21existential_transform12wrap_foo_ncp1aSiAA19SomeNoClassProtocol_p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SomeNoClassProtocol> (@in_guaranteed τ_0_0) -> Int
// CHECK: open_existential_addr
// CHECK: apply
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform3ncpyyF'
@inline(never) func ncp() {
let magic2:SomeNoClassProtocol = SomeNoClass()
let _ = wrap_foo_ncp(a:magic2)
}
/// Class Protocol Composition
internal protocol SomeClassProtocolComp : class {
func foo() -> Int
}
internal protocol SomeOtherClassProtocolComp : class {
func bar() -> Int
}
internal class SomeClassComp: SomeClassProtocolComp, SomeOtherClassProtocolComp {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
@inline(never) func bar() -> Int {
return 20
}
}
@inline(never) internal func wrap_foo_bar_cpc(a:SomeClassProtocolComp & SomeOtherClassProtocolComp) -> Int{
return a.foo() + a.bar()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform3cpcyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: init_existential_ref
// CHECK: debug_value
// CHECK: function_ref @$s21existential_transform16wrap_foo_bar_cpc1aSiAA21SomeClassProtocolComp_AA0g5OtherhiJ0p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SomeClassProtocolComp, τ_0_0 : SomeOtherClassProtocolComp> (@guaranteed τ_0_0) -> Int
// CHECK: open_existential_ref
// CHECK: apply
// CHECK: set_deallocating
// CHECK: debug_value
// CHECK: debug_value
// CHECK: dealloc_ref
// CHECK: dealloc_ref
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform3cpcyyF'
@inline(never) func cpc() {
let magic3:SomeClassProtocolComp & SomeOtherClassProtocolComp = SomeClassComp()
let _ = wrap_foo_bar_cpc(a:magic3)
}
/// Non Class Protocol Comp
internal protocol SomeNoClassProtocolComp {
func foo() -> Int
}
internal protocol SomeOtherNoClassProtocolComp {
func bar() -> Int
}
internal class SomeNoClassComp: SomeNoClassProtocolComp, SomeOtherNoClassProtocolComp {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
@inline(never) func bar() -> Int {
return 20
}
}
@inline(never) internal func wrap_no_foo_bar_comp_ncpc(a:SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp) -> Int{
return a.foo() + a.bar()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform4ncpcyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_stack
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: init_existential_addr
// CHECK: store
// CHECK: function_ref @$s21existential_transform25wrap_no_foo_bar_comp_ncpc1aSiAA23SomeNoClassProtocolComp_AA0i5OtherjklM0p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SomeNoClassProtocolComp, τ_0_0 : SomeOtherNoClassProtocolComp> (@in_guaranteed τ_0_0) -> Int
// CHECK: open_existential_addr
// CHECK: apply
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform4ncpcyyF'
@inline(never) func ncpc() {
let magic4:SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp = SomeNoClassComp()
let _ = wrap_no_foo_bar_comp_ncpc(a:magic4)
}
internal protocol P : class {
func foo() -> Int
}
internal class K : P {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform18do_not_optimize_cp1aSiAA1P_p_tF : $@convention(thin) (@guaranteed P) -> Int {
// CHECK: bb0(%0 : $P):
// CHECK: debug_value
// CHECK: [[O1:%.*]] = open_existential_ref
// CHECK: witness_method $@opened("{{.*}}") P, #P.foo!1 : <Self where Self : P> (Self) -> () -> Int, [[O1]] : $@opened("{{.*}}") P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> Int
// CHECK: apply
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform18do_not_optimize_cp1aSiAA1P_p_tF'
@inline(never) internal func do_not_optimize_cp(a:P ) -> Int{
return a.foo()
}
internal protocol PP : class {
func foo() -> Int
}
internal class KK : PP {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform13wrap_inout_cp1aSiAA2PP_pz_tF : $@convention(thin) (@inout PP) -> Int {
// CHECK: bb0(%0 : $*PP):
// CHECK: debug_value_addr
// CHECK: load
// CHECK: [[O1:%.*]] = open_existential_ref
// CHECK: witness_method $@opened("{{.*}}") PP, #PP.foo!1 : <Self where Self : PP> (Self) -> () -> Int, %3 : $@opened("{{.*}}PP : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> Int
// CHECK: apply
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform13wrap_inout_cp1aSiAA2PP_pz_tF'
@inline(never) internal func wrap_inout_cp(a: inout PP ) -> Int{
return a.foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform24do_not_optimize_inout_cpyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_stack
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: init_existential_ref
// CHECK: store
// CHECK: function_ref @$s21existential_transform13wrap_inout_cp1aSiAA2PP_pz_tF : $@convention(thin) (@inout PP) -> Int
// CHECK: apply
// CHECK: set_deallocating
// CHECK: debug_value
// CHECK: debug_value
// CHECK: dealloc_ref
// CHECK: dealloc_ref
// CHECK: dealloc_stack
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform24do_not_optimize_inout_cpyyF'
@inline(never) func do_not_optimize_inout_cp() {
var magic5:PP = KK()
let _ = wrap_inout_cp(a: &magic5)
}
internal protocol PPP {
func foo() -> Int
}
internal class KKKClass : PPP {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
}
@inline(never) internal func wrap_inout_ncp(a: inout PPP ) -> Int{
return a.foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform9inout_ncpyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_stack
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: init_existential_addr
// CHECK: store
// CHECK: function_ref @$s21existential_transform14wrap_inout_ncp1aSiAA3PPP_pz_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : PPP> (@inout τ_0_0) -> Int
// CHECK: open_existential_addr
// CHECK: apply
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform9inout_ncpyyF'
@inline(never) func inout_ncp() {
var magic6:PPP = KKKClass()
let _ = wrap_inout_ncp(a: &magic6)
}
internal protocol PPPP {
func foo() -> Int
}
internal struct SSSS : PPPP {
init() {
}
@inline(never) func foo() -> Int {
return 10
}
}
@inline(never) internal func wrap_struct_inout_ncp(a: inout PPPP ) -> Int{
return a.foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform16struct_inout_ncpyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: alloc_stack
// CHECK: struct
// CHECK: init_existential_addr
// CHECK: store
// CHECK: function_ref @$s21existential_transform21wrap_struct_inout_ncp1aSiAA4PPPP_pz_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : PPPP> (@inout τ_0_0) -> Int
// CHECK: open_existential_addr
// CHECK: apply
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: tuple
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform16struct_inout_ncpyyF'
@inline(never) func struct_inout_ncp() {
var magic7:PPPP = SSSS()
let _ = wrap_struct_inout_ncp(a: &magic7)
}
protocol GP {
func foo() -> Int
}
class GC: GP {
@inline(never) func foo() ->Int {
return 10
}
}
func wrap_gcp<T:GP>(_ a:T,_ b:GP) -> Int {
return a.foo() + b.foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform3gcpySixAA2GPRzlF : $@convention(thin) <T where T : GP> (@in_guaranteed T) -> Int {
// CHECK: bb0(%0 : $*T):
// CHECK: debug_value_addr
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: debug_value
// CHECK: alloc_stack
// CHECK: init_existential_addr
// CHECK: store
// CHECK: function_ref @$s21existential_transform8wrap_gcpySix_AA2GP_ptAaCRzlFTf4ne_n : $@convention(thin) <τ_0_0 where τ_0_0 : GP><τ_1_0 where τ_1_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0) -> Int
// CHECK: open_existential_addr
// CHECK: strong_retain
// CHECK: apply
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: strong_release
// CHECK: return
// CHECK: } // end sil function '$s21existential_transform3gcpySixAA2GPRzlF'
@inline(never) func gcp<T:GP>(_ a:T) -> Int {
let k:GC = GC()
return wrap_gcp(a, k)
}
func wrap_gcp_arch<T:GP>(_ a:T,_ b:GP, _ c:inout Array<T>) -> Int {
return a.foo() + b.foo() + c[0].foo()
}
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform8gcp_archySix_SayxGztAA2GPRzlF : $@convention(thin) <T where T : GP> (@in_guaranteed T, @inout Array<T>) -> Int {
// CHECK: bb0(%0 : $*T, %1 : $*Array<T>):
// CHECK: debug_value_addr
// CHECK: debug_value_addr
// CHECK: alloc_ref
// CHECK: debug_value
// CHECK: debug_value
// CHECK: alloc_stack
// CHECK: init_existential_addr
// CHECK: store
// CHECK: function_ref @$s21existential_transform13wrap_gcp_archySix_AA2GP_pSayxGztAaCRzlFTf4nen_n : $@convention(thin) <τ_0_0 where τ_0_0 : GP><τ_1_0 where τ_1_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @inout Array<τ_0_0>) -> Int
// CHECK: open_existential_addr
// CHECK: strong_retain
// CHECK: apply
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: strong_release
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform8gcp_archySix_SayxGztAA2GPRzlF'
@inline(never) func gcp_arch<T:GP>(_ a:T, _ b:inout Array<T>) -> Int {
let k:GC = GC()
return wrap_gcp_arch(a, k, &b)
}
protocol Foo {
var myName: String { get }
}
struct MyURL {
}
extension MyURL : Foo {
var myName : String { return "MyURL" }
}
struct MyStruct : Foo {
var myName : String { return "MyStruct" }
}
// CHECK-LABEL: sil shared [noinline] @$s21existential_transform7getNameySSAA3Foo_pFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : Foo> (@in_guaranteed τ_0_0) -> @owned String {
// CHECK: bb0(%0 : $*τ_0_0):
// CHECK: alloc_stack
// CHECK: init_existential_addr
// CHECK: copy_addr
// CHECK: debug_value_addr
// CHECK: open_existential_addr
// CHECK: witness_method
// CHECK: apply
// CHECK: dealloc_stack
// CHECK: return
// CHECK-LABEL: } // end sil function '$s21existential_transform7getNameySSAA3Foo_pFTf4e_n'
@inline(never) func getName(_ f: Foo) -> String {
return f.myName
}
@inline(never) func getName_wrapper() -> Int32{
let u = MyURL()
return getName(u) == "MyStruct" ? 0 : 1
}
protocol RP {
var val:Int32 {get set}
}
class RC: RP {
var val:Int32
init(val:Int32) { self.val = val }
}
// Note: The checks below must ensure that the function signature "@inline(never) func find(base:Int32, mult:Int32, Obj1: RP) -> Bool" has been turned into a protocol-constrained generic function via existential specialization, i.e., "function_ref @$s21existential_transform4find4base4mult4Obj1Sbs5Int32V_AgA2RP_ptFTf4nne_n : $@convention(thin) <τ_0_0 where τ_0_0 : RP> (Int32, Int32, @in_guaranteed τ_0_0) -> Bool". Same is true for the recursive function call for "return find (base: base, mult: mult+1, Obj1: Obj1)". Please refer to existential_specializer_soletype.sil test for SIL level testing. This test makes sure that nothing else breaks when we run end-to-end.
// CHECK-LABEL: sil shared [noinline] @$s21existential_transform4find4base4mult4Obj1Sbs5Int32V_AgA2RP_ptFTf4nne_n : $@convention(thin) <τ_0_0 where τ_0_0 : RP> (Int32, Int32, @in_guaranteed τ_0_0) -> Bool {
// CHECK: bb0
// CHECK: alloc_stack $RP
// CHECK: init_existential_addr
// CHECK: copy_addr
// CHECK: debug_value
// CHECK: debug_value
// CHECK: debug_value_addr
// CHECK: struct_extract
// CHECK: struct_extract
// CHECK: integer_literal
// CHECK: builtin
// CHECK: tuple_extract
// CHECK: tuple_extract
// CHECK: cond_fail
// CHECK: open_existential_addr
// CHECK: witness_method
// CHECK: apply
// CHECK: struct_extract
// CHECK: builtin
// CHECK: cond_br
// CHECK: bb1:
// CHECK: integer_literal
// CHECK: struct
// CHECK: br
// CHECK: bb2:
// CHECK: open_existential_addr
// CHECK: witness_method
// CHECK: apply
// CHECK: struct_extract
// CHECK: builtin
// CHECK: cond_br
// CHECK: bb3
// CHECK: dealloc_stack
// CHECK: return
// CHECK: bb4:
// CHECK: struct
// CHECK: br
// CHECK: bb5:
// CHECK: integer_literal
// CHECK: builtin
// CHECK: tuple_extract
// CHECK: tuple_extract
// CHECK: cond_fail
// CHECK: struct
// CHECK: function_ref @$s21existential_transform4find4base4mult4Obj1Sbs5Int32V_AgA2RP_ptFTf4nne_n : $@convention(thin) <τ_0_0 where τ_0_0 : RP> (Int32, Int32, @in_guaranteed τ_0_0) -> Bool
// CHECK: open_existential_addr
// CHECK: apply
// CHECK: br
// CHECK-LABEL: } // end sil function '$s21existential_transform4find4base4mult4Obj1Sbs5Int32V_AgA2RP_ptFTf4nne_n'
@inline(never) func find(base:Int32, mult:Int32, Obj1: RP) -> Bool {
if base * mult > Obj1.val {
return false
} else if base * mult == Obj1.val {
return true
} else {
return find (base: base, mult: mult+1, Obj1: Obj1)
}
}
@inline(never) func find_wrapper() -> Bool {
let ab = RC(val: 100)
return find(base: 3, mult: 1, Obj1: ab)
}
@_optimize(none) public func foo() -> Int {
cp()
ncp()
cpc()
ncpc()
let p:P = K()
let x:Int = do_not_optimize_cp(a:p)
do_not_optimize_inout_cp()
inout_ncp()
struct_inout_ncp()
let y:Int = gcp(GC())
var a:Array<GC> = [GC()]
let z:Int = gcp_arch(GC(), &a)
let zz:Int32 = getName_wrapper()
let _ = find_wrapper()
return x + y + z + Int(zz)
}