// Test .swiftmodule with library-evolution // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -module-name A -emit-module-path %t/A.swiftmodule -enable-library-evolution -swift-version 5 %S/Inputs/specialize_attr_module.swift // RUN: %target-swift-frontend -I %t -module-name B -emit-module-path %t/B.swiftmodule -enable-library-evolution -swift-version 5 %S/Inputs/specialize_attr_module2.swift // RUN: %target-swift-emit-silgen -I %t -module-name specialize_attr -emit-verbose-sil %s -swift-version 5 | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-os // RUN: %target-swift-emit-sil -I %t -sil-verify-all -O -module-name specialize_attr -emit-verbose-sil %s | %FileCheck -check-prefix=CHECK-OPT -check-prefix=CHECK-OPT-EVO -check-prefix=CHECK-OPT-%target-os %s // Test .swiftinterface // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o /dev/null -module-name A -emit-module-interface-path %t/A.swiftinterface -enable-library-evolution -swift-version 5 %S/Inputs/specialize_attr_module.swift // RUN: %target-swift-frontend -emit-module -o /dev/null -I %t -module-name B -emit-module-interface-path %t/B.swiftinterface -enable-library-evolution -swift-version 5 %S/Inputs/specialize_attr_module2.swift // RUN: %target-swift-emit-silgen -I %t -module-name specialize_attr -emit-verbose-sil %s -swift-version 5 | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-os // RUN: %target-swift-emit-sil -I %t -sil-verify-all -O -module-name specialize_attr -emit-verbose-sil %s | %FileCheck -check-prefix=CHECK-OPT -check-prefix=CHECK-OPT-EVO %s // Test .swiftmodule without library-evolution // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -module-name A -emit-module-path %t/A.swiftmodule -swift-version 5 %S/Inputs/specialize_attr_module.swift // RUN: %target-swift-frontend -I %t -module-name B -emit-module-path %t/B.swiftmodule -swift-version 5 %S/Inputs/specialize_attr_module2.swift // RUN: %target-swift-emit-silgen -I %t -module-name specialize_attr -emit-verbose-sil %s -swift-version 5 | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-os // RUN: %target-swift-emit-sil -I %t -sil-verify-all -O -module-name specialize_attr -emit-verbose-sil %s | %FileCheck -check-prefix=CHECK-OPT -check-prefix=CHECK-OPT-NOEVO %s import A import B // CHECK: @_specialize(exported: false, kind: full, where T == Int, U == Float) // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == Klass1, U == FakeString) // CHECK-NEXT: func specializeThis(_ t: T, u: U) @_specialize(where T == Int, U == Float) @_specialize(where T == Klass1, U == FakeString) public func specializeThis(_ t: T, u: U) {} // CHECK: @_specialize(exported: false, kind: full, where T == Klass1, U == FakeString) // CHECK-NEXT: func specializeThis2(_ t: __owned T, u: __owned U) -> (T, U) @_specialize(where T == Klass1, U == FakeString) public func specializeThis2(_ t: __owned T, u: __owned U) -> (T, U) { (t, u) } public protocol PP { associatedtype PElt } public protocol QQ { associatedtype QElt } public struct RR : PP { public typealias PElt = Float } public struct SS : QQ { public typealias QElt = Int } public class Klass1 {} public class FakeStringData {} public struct FakeString { var f: FakeStringData? = nil } public struct RRNonTrivial : PP { public typealias PElt = Klass1 var elt: Klass1? = nil } public struct SSNonTrivial : QQ { public typealias QElt = FakeString var elt: FakeString? = nil } public struct GG { var t: T } // CHECK-LABEL: public class CC where T : PP { public class CC { // CHECK-NEXT: var k: Klass1? // To make non-trivial var k: Klass1? = nil // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RR, U == SS) // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RRNonTrivial, U == SSNonTrivial) // CHECK-NEXT: @inline(never) public func foo(_ u: U, g: GG) -> (U, GG) where U : QQ @inline(never) @_specialize(where T == RR, U == SS) @_specialize(where T == RRNonTrivial, U == SSNonTrivial) public func foo(_ u: U, g: GG) -> (U, GG) { return (u, g) } // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RR, U == SS) // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RRNonTrivial, U == SSNonTrivial) // CHECK-NEXT: @inline(never) public func foo2(_ u: __owned U, g: __owned GG) -> (U, GG) where U : QQ @inline(never) @_specialize(where T == RR, U == SS) @_specialize(where T == RRNonTrivial, U == SSNonTrivial) public func foo2(_ u: __owned U, g: __owned GG) -> (U, GG) { return (u, g) } } // CHECK-LABEL: public struct CC2 where T : PP { public struct CC2 { // CHECK-NEXT: var k: Klass1? // To make non-trivial var k: Klass1? = nil // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RR, U == SS) // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RRNonTrivial, U == SSNonTrivial) // CHECK-NEXT: @inline(never) public mutating func foo(_ u: U, g: GG) -> (U, GG) where U : QQ @inline(never) @_specialize(where T == RR, U == SS) @_specialize(where T == RRNonTrivial, U == SSNonTrivial) mutating public func foo(_ u: U, g: GG) -> (U, GG) { return (u, g) } // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RR, U == SS) // CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RRNonTrivial, U == SSNonTrivial) // CHECK-NEXT: @inline(never) public mutating func foo2(_ u: __owned U, g: __owned GG) -> (U, GG) where U : QQ @inline(never) @_specialize(where T == RR, U == SS) @_specialize(where T == RRNonTrivial, U == SSNonTrivial) mutating public func foo2(_ u: __owned U, g: __owned GG) -> (U, GG) { return (u, g) } } // Import from module A and B. // CHECK-OPT-macosx-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Double] [_specialize exported: true, kind: full, available: 10.50, where T == Int16] [_specialize exported: true, kind: full, where T == Int] @$s1A11PublicThingV11doStuffWithyyxF : $@convention(method) (@in_guaranteed T, PublicThing) -> () // CHECK-OPT-linux-gnu-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Double] [_specialize exported: true, kind: full, where T == Int16] [_specialize exported: true, kind: full, where T == Int] @$s1A11PublicThingV11doStuffWithyyxF : $@convention(method) (@in_guaranteed T, PublicThing) -> () // CHECK-OPT-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Double] [_specialize exported: true, kind: full, where T == Int] @$s1A13InternalThingV11doStuffWith5boxedyAA05BoxedB0VyxG_tF : $@convention(method) (BoxedThing, InternalThing) -> () // CHECK-OPT-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Int] @$s1A14InternalThing2V9computedZxvM : $@yield_once @convention(method) (@inout InternalThing2) -> @yields @inout T // CHECK-OPT-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Int] @$s1A14InternalThing2V9computedZxvr : $@yield_once @convention(method) (@in_guaranteed InternalThing2) -> @yields @in_guaranteed T // CHECK-OPT-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Int] @$s1A14InternalThing2VyxSicig : $@convention(method) (Int, @in_guaranteed InternalThing2) -> @out T // CHECK-OPT-DAG: sil {{.*}} [_specialize exported: true, kind: full, where T == Int] @$s1A14InternalThing2VyxSicis : $@convention(method) (@in T, Int, @inout InternalThing2) -> () // CHECK-LABEL: sil [_specialize exported: false, kind: full, where T == Klass1, U == FakeString] [_specialize exported: false, kind: full, where T == Int, U == Float] [ossa] @$s15specialize_attr0A4This_1uyx_q_tr0_lF : $@convention(thin) (@in_guaranteed T, @in_guaranteed U) -> () { // CHECK-OPT-DAG: sil shared [noinline] {{.*}}@$s15specialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lFAA12RRNonTrivialV_AA05SSNonH0VTg5 : $@convention(method) (@guaranteed SSNonTrivial, @guaranteed GG, @guaranteed CC) -> (@owned SSNonTrivial, @out GG) { // CHECK-OPT-DAG: sil shared [noinline] {{.*}}@$s15specialize_attr2CCC4foo2_1gqd___AA2GGVyxGtqd__n_AHntAA2QQRd__lFAA2RRV_AA2SSVTg5 : $@convention(method) (SS, GG, @guaranteed CC) -> (SS, @out GG) { // CHECK-OPT-DAG: sil [noinline] {{.*}}@$s15specialize_attr2CCC4foo2_1gqd___AA2GGVyxGtqd__n_AHntAA2QQRd__lF : $@convention(method) (@in U, @in GG, @guaranteed CC) -> (@out U, @out GG) { // CHECK-LABEL: sil [noinline] [_specialize exported: false, kind: full, where T == RRNonTrivial, U == SSNonTrivial] [_specialize exported: false, kind: full, where T == RR, U == SS] [ossa] @$s15specialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) (@in_guaranteed U, @in_guaranteed GG, @guaranteed CC) -> (@out U, @out GG) { // ----------------------------------------------------------------------------- // Test user-specialized subscript accessors. public protocol TestSubscriptable { associatedtype Element subscript(i: Int) -> Element { get set } } public class ASubscriptable : TestSubscriptable { var storage: UnsafeMutablePointer init(capacity: Int) { storage = UnsafeMutablePointer.allocate(capacity: capacity) } public subscript(i: Int) -> Element { @_specialize(where Element == Int) @_specialize(where Element == Klass1) get { return storage[i] } @_specialize(where Element == Int) @_specialize(where Element == Klass1) set(rhs) { storage[i] = rhs } } } // ASubscriptable.subscript.getter with _specialize // CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Klass1] [_specialize exported: false, kind: full, where Element == Int] [ossa] @$s15specialize_attr14ASubscriptableCyxSicig : $@convention(method) (Int, @guaranteed ASubscriptable) -> @out Element { // ASubscriptable.subscript.setter with _specialize // CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Klass1] [_specialize exported: false, kind: full, where Element == Int] [ossa] @$s15specialize_attr14ASubscriptableCyxSicis : $@convention(method) (@in Element, Int, @guaranteed ASubscriptable) -> () { // ASubscriptable.subscript.modify with no attribute // CHECK-LABEL: sil [transparent] [serialized] [ossa] @$s15specialize_attr14ASubscriptableCyxSiciM : $@yield_once @convention(method) (Int, @guaranteed ASubscriptable) -> @yields @inout Element { public class Addressable : TestSubscriptable { var storage: UnsafeMutablePointer init(capacity: Int) { storage = UnsafeMutablePointer.allocate(capacity: capacity) } public subscript(i: Int) -> Element { @_specialize(where Element == Int) @_specialize(where Element == Klass1) unsafeAddress { return UnsafePointer(storage + i) } @_specialize(where Element == Int) @_specialize(where Element == Klass1) unsafeMutableAddress { return UnsafeMutablePointer(storage + i) } } } // Addressable.subscript.unsafeAddressor with _specialize // CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Klass1] [_specialize exported: false, kind: full, where Element == Int] [ossa] @$s15specialize_attr11AddressableCyxSicilu : $@convention(method) (Int, @guaranteed Addressable) -> UnsafePointer { // Addressable.subscript.unsafeMutableAddressor with _specialize // CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Klass1] [_specialize exported: false, kind: full, where Element == Int] [ossa] @$s15specialize_attr11AddressableCyxSiciau : $@convention(method) (Int, @guaranteed Addressable) -> UnsafeMutablePointer { // Addressable.subscript.getter with no attribute // CHECK-LABEL: sil [transparent] [serialized] [ossa] @$s15specialize_attr11AddressableCyxSicig : $@convention(method) (Int, @guaranteed Addressable) -> @out Element { // Addressable.subscript.setter with no attribute // CHECK-LABEL: sil [transparent] [serialized] [ossa] @$s15specialize_attr11AddressableCyxSicis : $@convention(method) (@in Element, Int, @guaranteed Addressable) -> () { // Addressable.subscript.modify with no attribute // CHECK-LABEL: sil [transparent] [serialized] [ossa] @$s15specialize_attr11AddressableCyxSiciM : $@yield_once @convention(method) (Int, @guaranteed Addressable) -> @yields @inout Element { public struct TestPrespecialized { // CHECK-LABEL: sil [_specialize exported: true, kind: full, where T == Double] [_specialize exported: true, kind: full, where T == Int] [ossa] @$s15specialize_attr18TestPrespecializedV5aFuncyyF : $@convention(method) (TestPrespecialized) -> () { @_specialize(exported: true, where T == Int) @_specialize(exported: true, where T == Double) public func aFunc() {} } extension TestPrespecialized { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s15specialize_attr18TestPrespecializedV5aFuncyyF", where T == Int32] [ossa] @$s15specialize_attr18TestPrespecializedV0A6TargetyyF : $@convention(method) (TestPrespecialized) -> () { @_specialize(exported: true, kind: full, target: aFunc(), where T == Int32) public func specializeTarget() {} } extension PublicThing { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A11PublicThingV11doStuffWithyyxF", where T == PublicPlainThing] [_specialize exported: true, kind: full, target: "$s1A11PublicThingV11doStuffWithyyxF", where T == Float] [ossa] @$s1A11PublicThingV15specialize_attrE17specializedoStuffyyxF : $@convention(method) (@in_guaranteed T, PublicThing) -> () { // CHECK-OPT-DAG: sil @$s1A11PublicThingV11doStuffWithyyxFAA0a5PlainB0V_Ts5 : $@convention(method) (PublicPlainThing, PublicThing) -> () { // CHECK-OPT-DAG: sil @$s1A11PublicThingV11doStuffWithyyxFSf_Ts5 : $@convention(method) (Float, PublicThing) -> () { @_specialize(exported: true, kind: full, target: doStuffWith(_:), where T == Float) @_specialize(exported: true, kind: full, target: doStuffWith(_:), where T == PublicPlainThing) public func specializedoStuff(_ t: T) {} } @_specializeExtension extension InternalThing { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A13InternalThingV11doStuffWithyyxF", where T == PublicPlainThing] [ossa] @$s1A13InternalThingV15specialize_attrE18specializedDoStuffyyxF : $@convention(method) (@in_guaranteed T, InternalThing) -> () { // CHECK-OPT-DAG: sil @$s1A13InternalThingV11doStuffWithyyxFAA011PublicPlainB0V_Ts5 : $@convention(method) (PublicPlainThing, InternalThing) -> () { @_specialize(exported: true, kind: full, target: doStuffWith(_:), where T == PublicPlainThing) public func specializedDoStuff(_ t: T) {} // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A13InternalThingV11doStuffWith5boxedyAA05BoxedB0VyxG_tF", where T == PublicPlainThing] [ossa] @$s1A13InternalThingV15specialize_attrE22specializedDoStuffWith5boxedyAA05BoxedB0VyxG_tF : $@convention(method) (BoxedThing, InternalThing) -> () { // CHECK-OPT-DAG: sil @$s1A13InternalThingV11doStuffWith5boxedyAA05BoxedB0VyxG_tFAA011PublicPlainB0V_Ts5 : $@convention(method) (BoxedThing, InternalThing) -> () { @_specialize(exported: true, target:doStuffWith(boxed:), where T == PublicPlainThing) public func specializedDoStuffWith(boxed: BoxedThing) {} // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tF", where T == ResilientThing] [_specialize exported: true, kind: full, target: "$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tF", where T == Int16] [_specialize exported: true, kind: full, target: "$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tF", where T == Klass1] [ossa] @$s1A13InternalThingV15specialize_attrE23specializedDoStuffWith26boxed2yAA11BoxedThing2VyxG_tF : $@convention(method) (@in_guaranteed BoxedThing2, InternalThing) -> () { // CHECK-OPT-EVO-DAG: sil @$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tFAA09ResilientB0V_Ts5 : $@convention(method) (@in_guaranteed BoxedThing2, InternalThing) -> () { // CHECK-OPT-NOEVO-DAG: sil @$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tFAA09ResilientB0V_Ts5 : $@convention(method) (BoxedThing2, InternalThing) -> () { // CHECK-OPT-DAG: sil @$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tFs5Int16V_Ts5 : $@convention(method) (BoxedThing2, InternalThing) -> () { // CHECK-OPT-DAG: sil @$s1A13InternalThingV11doStuffWith6boxed2yAA11BoxedThing2VyxG_tF15specialize_attr6Klass1C_Ts5 : $@convention(method) (@guaranteed BoxedThing2, InternalThing) -> () { @_specialize(exported: true, target:doStuffWith(boxed2:), where T == Klass1) @_specialize(exported: true, target:doStuffWith(boxed2:), where T == Int16) @_specialize(exported: true, target:doStuffWith(boxed2:), where T == ResilientThing) public func specializedDoStuffWith2(boxed2: BoxedThing2) {} } @_specializeExtension extension InternalThing2 { public var specializeComputedX : T { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2V9computedXxvg", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE0C9ComputedXxvg : $@convention(method) (@in_guaranteed InternalThing2) -> @out T { // CHECK-OPT-DAG: sil {{.*}}@$s1A14InternalThing2V9computedXxvg15specialize_attr6Klass1C_Ts5 : $@convention(method) (@guaranteed InternalThing2) -> @owned Klass1 { @_specialize(exported: true, target: computedX, where T == Klass1) get { fatalError("don't call") } } public var specializeComputedY : T { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2V9computedYxvg", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE0C9ComputedYxvg : $@convention(method) (@in_guaranteed InternalThing2) -> @out T { // CHECK-OPT-DAG: sil {{.*}}@$s1A14InternalThing2V9computedYxvg15specialize_attr6Klass1C_Ts5 : $@convention(method) (@guaranteed InternalThing2) -> @owned Klass1 { @_specialize(exported: true, target: computedY, where T == Klass1) get { fatalError("don't call") } // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2V9computedYxvs", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE0C9ComputedYxvs : $@convention(method) (@in T, @inout InternalThing2) -> () { // CHECK-OPT-DAG: sil {{.*}}@$s1A14InternalThing2V9computedYxvs15specialize_attr6Klass1C_Ts5 : $@convention(method) (@owned Klass1, @inout InternalThing2) -> () { @_specialize(exported: true, target: computedY, where T == Klass1) set {} } public var specializeComputedZ : T { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2V9computedZxvM", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE0C9ComputedZxvM : $@yield_once @convention(method) (@inout InternalThing2) -> @yields @inout T { // CHECK-OPT-DAG: sil @$s1A14InternalThing2V9computedZxvM15specialize_attr6Klass1C_Ts5 : $@yield_once @convention(method) (@inout InternalThing2) -> @yields @inout Klass1 { @_specialize(exported: true, target: computedZ, where T == Klass1) _modify { fatalError("don't call") } // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2V9computedZxvr", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE0C9ComputedZxvr : $@yield_once @convention(method) (@in_guaranteed InternalThing2) -> @yields @in_guaranteed T { // CHECK-OPT-DAG: sil @$s1A14InternalThing2V9computedZxvr15specialize_attr6Klass1C_Ts5 : $@yield_once @convention(method) (@guaranteed InternalThing2) -> @yields @in_guaranteed Klass1 { @_specialize(exported: true, target: computedZ, where T == Klass1) _read { fatalError("don't call") } } public subscript(specialized i: Int) -> T { // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2VyxSicig", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE11specializedxSi_tcig : $@convention(method) (Int, @in_guaranteed InternalThing2) -> @out T { // CHECK-OPT-DAG: sil {{.*}}@$s1A14InternalThing2VyxSicig15specialize_attr6Klass1C_Ts5 : $@convention(method) (Int, @guaranteed InternalThing2) -> @owned Klass1 { @_specialize(exported: true, target: subscript(_:), where T == Klass1) get { fatalError("don't call") } // CHECK-LABEL: sil [_specialize exported: true, kind: full, target: "$s1A14InternalThing2VyxSicis", where T == Klass1] [ossa] @$s1A14InternalThing2V15specialize_attrE11specializedxSi_tcis : $@convention(method) (@in T, Int, @inout InternalThing2) -> () { // CHECK-OPT-DAG: sil {{.*}}@$s1A14InternalThing2VyxSicis15specialize_attr6Klass1C_Ts5 : $@convention(method) (@owned Klass1, Int, @inout InternalThing2) -> () { @_specialize(exported: true, target: subscript(_:), where T == Klass1) set { fatalError("don't call") } } }