mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
These were added in https://github.com/swiftlang/swift/pull/81375 (and several other follow-up PRs because we missed a few places) and are no longer needed.
897 lines
44 KiB
Plaintext
897 lines
44 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -eager-specializer %s | %FileCheck %s
|
|
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -eager-specializer %s -o %t.sil && %target-swift-frontend -module-name=eager_specialize -emit-ir %t.sil | %FileCheck --check-prefix=CHECK-IRGEN %s
|
|
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -eager-specializer -sil-inline-generics=true -inline %s | %FileCheck --check-prefix=CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE %s
|
|
|
|
// XFAIL: CPU=arm64e
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
import SwiftShims
|
|
|
|
public protocol AnElt {
|
|
}
|
|
|
|
public protocol HasElt {
|
|
associatedtype Elt
|
|
init(e: Elt)
|
|
}
|
|
|
|
struct X : AnElt {
|
|
@_hasStorage var i: Int { get set }
|
|
init(i: Int)
|
|
}
|
|
|
|
struct S : HasElt {
|
|
typealias Elt = X
|
|
@_hasStorage var e: X { get set }
|
|
init(e: Elt)
|
|
}
|
|
|
|
public struct G<Container : HasElt> {
|
|
public func getContainer(e: Container.Elt) -> Container
|
|
init()
|
|
}
|
|
|
|
// CHECK: @_specialize(exported: false, kind: full, where T == S)
|
|
// CHECK: public func getGenericContainer<T>(g: G<T>, e: T.Elt) -> T where T : HasElt, T.Elt : AnElt
|
|
@_specialize(where T == S)
|
|
public func getGenericContainer<T>(g: G<T>, e: T.Elt) -> T where T.Elt : AnElt
|
|
|
|
enum ArithmeticError : Error {
|
|
case DivByZero
|
|
func hash(into hasher: inout Hasher)
|
|
var _code: Int { get }
|
|
}
|
|
|
|
// CHECK: @_specialize(exported: false, kind: full, where T == Int)
|
|
// CHECK: public func divideNum<T>(num: T, den: T) throws -> T where T : SignedInteger, T : _ExpressibleByBuiltinIntegerLiteral
|
|
@_specialize(where T == Int)
|
|
public func divideNum<T : SignedInteger & _ExpressibleByBuiltinIntegerLiteral>(num: T, den: T) throws -> T
|
|
|
|
@inline(never) @_optimize(none) func foo<T>(t: T) -> Int64
|
|
|
|
// CHECK: @_specialize(exported: false, kind: full, where T == Int64)
|
|
// CHECK: @_specialize(exported: false, kind: full, where T == Float)
|
|
// CHECK: public func voidReturn<T>(t: T)
|
|
@_specialize(where T == Int64)
|
|
@_specialize(where T == Float)
|
|
public func voidReturn<T>(t: T)
|
|
|
|
// CHECK: @_specialize(exported: false, kind: full, where T == Int64)
|
|
// CHECK: @_specialize(exported: false, kind: full, where T == Float)
|
|
// CHECK: public func nonvoidReturn<T>(t: T) -> Int64
|
|
@_specialize(where T == Int64)
|
|
@_specialize(where T == Float)
|
|
public func nonvoidReturn<T>(t: T) -> Int64
|
|
|
|
// --- test: protocol conformance, substitution for dependent types
|
|
// non-layout dependent generic arguments, emitUncheckedBitCast (non
|
|
// address-type)
|
|
|
|
// Helper
|
|
//
|
|
// G.getContainer(A.Elt) -> A
|
|
sil @$s16eager_specialize1GV12getContaineryx3EltQzF : $@convention(method) <Container where Container : HasElt> (@in Container.Elt, G<Container>) -> @out Container {
|
|
bb0(%0 : $*Container, %1 : $*Container.Elt, %2 : $G<Container>):
|
|
%4 = witness_method $Container, #HasElt.init!allocator : $@convention(witness_method: HasElt) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, @thick τ_0_0.Type) -> @out τ_0_0
|
|
%5 = metatype $@thick Container.Type
|
|
%6 = apply %4<Container>(%0, %1, %5) : $@convention(witness_method: HasElt) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, @thick τ_0_0.Type) -> @out τ_0_0
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
}
|
|
|
|
// getGenericContainer<A where ...> (G<A>, e : A.Elt) -> A
|
|
sil [_specialize where T == S] @$s16eager_specialize19getGenericContainer_1exAA1GVyxG_3EltQztAA03HasF0RzAA02AnF0AHRQlF : $@convention(thin) <T where T : HasElt, T.Elt : AnElt> (G<T>, @in T.Elt) -> @out T {
|
|
bb0(%0 : $*T, %1 : $G<T>, %2 : $*T.Elt):
|
|
// function_ref G.getContainer(A.Elt) -> A
|
|
%5 = function_ref @$s16eager_specialize1GV12getContaineryx3EltQzF : $@convention(method) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, G<τ_0_0>) -> @out τ_0_0
|
|
%6 = apply %5<T>(%0, %2, %1) : $@convention(method) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, G<τ_0_0>) -> @out τ_0_0
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
}
|
|
|
|
// Specialization getGenericContainer<S, X>
|
|
//
|
|
// CHECK-LABEL: sil shared @$s16eager_specialize19getGenericContainer_1exAA1GVyxG_3EltQztAA03HasF0RzAA02AnF0AHRQlF4main1SV_Tg5 : $@convention(thin) (G<S>, X) -> S {
|
|
// CHECK: bb0(%0 : $G<S>, %1 : $X):
|
|
// CHECK: return %{{.*}} : $S
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
//
|
|
// CHECK-LABEL: sil @$s16eager_specialize19getGenericContainer_1exAA1GVyxG_3EltQztAA03HasF0RzAA02AnF0AHRQlF : $@convention(thin) <T where T : HasElt, T.Elt : AnElt> (G<T>, @in T.Elt) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $G<T>, %2 : $*T.Elt):
|
|
// CHECK: %{{.*}} = metatype $@thick T.Type
|
|
// CHECK: %{{.*}} = metatype $@thick S.Type
|
|
// CHECK: %{{.*}} = unchecked_bitwise_cast %{{.*}} : $@thick T.Type to $Builtin.Word
|
|
// CHECK: %{{.*}} = unchecked_bitwise_cast %{{.*}} : $@thick S.Type to $Builtin.Word
|
|
// CHECK: %{{.*}} = builtin "cmp_eq_Word"(%{{.*}} : $Builtin.Word, %{{.*}} : $Builtin.Word) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb4, bb1
|
|
|
|
// CHECK: bb2:
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize1GV12getContaineryx3EltQzF : $@convention(method) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, G<τ_0_0>) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = apply %{{.*}}<T>(%0, %2, %1) : $@convention(method) <τ_0_0 where τ_0_0 : HasElt> (@in τ_0_0.Elt, G<τ_0_0>) -> @out τ_0_0
|
|
// CHECK: br bb3
|
|
|
|
// CHECK: bb3:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
|
|
// CHECK: bb4:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*T to $*S
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %1 : $G<T> to $G<S>
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*T.Elt to $*X
|
|
// CHECK: %{{.*}} = load %{{.*}} : $*X
|
|
// function_ref specialized getGenericContainer<A where ...> (G<A>, e : A.Elt) -> A
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize19getGenericContainer_1exAA1GVyxG_3EltQztAA03HasF0RzAA02AnF0AHRQlF4main1SV_Tg5 : $@convention(thin) (G<S>, X) -> S
|
|
// CHECK: %{{.*}} = apply %{{.*}}(%{{.*}}, %{{.*}}) : $@convention(thin) (G<S>, X) -> S
|
|
// CHECK: store %{{.*}} to %{{.*}} : $*S
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb3
|
|
|
|
// --- test: rethrow
|
|
|
|
// Helper
|
|
//
|
|
// static != infix<A where ...> (A, A) -> Bool
|
|
sil public_external [serialized] @$ss2neoiySbx_xts9EquatableRzlFZ : $@convention(thin) <T where T : Equatable> (@in T, @in T) -> Bool {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%4 = witness_method $T, #Equatable."==" : $@convention(witness_method: Equatable) <τ_0_0 where τ_0_0 : Equatable> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> Bool
|
|
%5 = metatype $@thick T.Type
|
|
%6 = apply %4<T>(%0, %1, %5) : $@convention(witness_method: Equatable) <τ_0_0 where τ_0_0 : Equatable> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> Bool
|
|
%7 = struct_extract %6 : $Bool, #Bool._value
|
|
%8 = integer_literal $Builtin.Int1, -1
|
|
%9 = builtin "xor_Int1"(%7 : $Builtin.Int1, %8 : $Builtin.Int1) : $Builtin.Int1
|
|
%10 = struct $Bool (%9 : $Builtin.Int1)
|
|
return %10 : $Bool
|
|
}
|
|
|
|
// divideNum<A where ...> (A, den : A) throws -> A
|
|
sil [_specialize where T == Int] @$s16eager_specialize9divideNum_3denxx_xtKs13SignedIntegerRzlF : $@convention(thin) <T where T : SignedInteger, T : _ExpressibleByBuiltinIntegerLiteral> (@in T, @in T) -> (@out T, @error any Error) {
|
|
bb0(%0 : $*T, %1 : $*T, %2 : $*T):
|
|
// function_ref static != infix<A where ...> (A, A) -> Bool
|
|
%5 = function_ref @$ss2neoiySbx_xts9EquatableRzlFZ : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@in τ_0_0, @in τ_0_0) -> Bool
|
|
%6 = alloc_stack $T
|
|
copy_addr %2 to [init] %6 : $*T
|
|
%8 = witness_method $T, #_ExpressibleByBuiltinIntegerLiteral.init!allocator : $@convention(witness_method: _ExpressibleByBuiltinIntegerLiteral) <τ_0_0 where τ_0_0 : _ExpressibleByBuiltinIntegerLiteral> (Builtin.IntLiteral, @thick τ_0_0.Type) -> @out τ_0_0
|
|
%9 = metatype $@thick T.Type
|
|
%10 = integer_literal $Builtin.IntLiteral, 0
|
|
%11 = alloc_stack $T
|
|
%12 = apply %8<T>(%11, %10, %9) : $@convention(witness_method: _ExpressibleByBuiltinIntegerLiteral) <τ_0_0 where τ_0_0 : _ExpressibleByBuiltinIntegerLiteral> (Builtin.IntLiteral, @thick τ_0_0.Type) -> @out τ_0_0
|
|
%13 = apply %5<T>(%6, %11) : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@in τ_0_0, @in τ_0_0) -> Bool
|
|
%14 = struct_extract %13 : $Bool, #Bool._value
|
|
dealloc_stack %11 : $*T
|
|
dealloc_stack %6 : $*T
|
|
cond_br %14, bb2, bb1
|
|
|
|
bb1:
|
|
destroy_addr %2 : $*T
|
|
destroy_addr %1 : $*T
|
|
%24 = alloc_existential_box $Error, $ArithmeticError
|
|
%25 = project_existential_box $ArithmeticError in %24 : $Error
|
|
%26 = enum $ArithmeticError, #ArithmeticError.DivByZero!enumelt
|
|
store %26 to %25 : $*ArithmeticError
|
|
throw %24 : $Error
|
|
|
|
bb2:
|
|
%18 = witness_method $T, #BinaryInteger."/" : $@convention(witness_method: BinaryInteger) <τ_0_0 where τ_0_0 : BinaryInteger> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
|
|
%19 = apply %18<T>(%0, %1, %2, %9) : $@convention(witness_method: BinaryInteger) <τ_0_0 where τ_0_0 : BinaryInteger> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
|
|
%20 = tuple ()
|
|
return %20 : $()
|
|
}
|
|
|
|
// specialized divideNum<A where ...> (A, den : A) throws -> A
|
|
// CHECK-LABEL: sil shared @$s16eager_specialize9divideNum_3denxx_xtKSZRzlFSi_Tg5 : $@convention(thin) (Int, Int) -> (Int, @error any Error) {
|
|
// CHECK: bb0(%0 : $Int, %1 : $Int):
|
|
// CHECK: return %{{.*}}
|
|
// CHECK: throw %{{.*}}
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
//
|
|
// CHECK-LABEL: sil @$s16eager_specialize9divideNum_3denxx_xtKs13SignedIntegerRzlF : $@convention(thin) <T where T : SignedInteger, T : _ExpressibleByBuiltinIntegerLiteral> (@in T, @in T) -> (@out T, @error any Error) {
|
|
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
|
|
// CHECK: %3 = metatype $@thick T.Type
|
|
// CHECK: %4 = metatype $@thick Int.Type
|
|
// CHECK: %5 = unchecked_bitwise_cast %3 : $@thick T.Type to $Builtin.Word
|
|
// CHECK: %6 = unchecked_bitwise_cast %4 : $@thick Int.Type to $Builtin.Word
|
|
// CHECK: %7 = builtin "cmp_eq_Word"(%5 : $Builtin.Word, %6 : $Builtin.Word) : $Builtin.Int1
|
|
// CHECK: cond_br %7, bb7, bb1
|
|
|
|
// CHECK: bb2:
|
|
// CHECK: // function_ref static != infix<A>(_:_:)
|
|
// CHECK: cond_br %{{.*}}, bb5, bb3
|
|
|
|
// CHECK: bb3:
|
|
// CHECK: br bb4(%{{.*}} : $any Error)
|
|
|
|
// CHECK: bb4(%{{.*}} : $any Error):
|
|
// CHECK: throw %{{.*}} : $any Error
|
|
|
|
// CHECK: bb5:
|
|
// CHECK: %{{.*}} = witness_method $T, #BinaryInteger."/" : {{.*}} : $@convention(witness_method: BinaryInteger) <τ_0_0 where τ_0_0 : BinaryInteger> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
|
|
// CHECK: apply %{{.*}}<T>({{.*}}) : $@convention(witness_method: BinaryInteger) <τ_0_0 where τ_0_0 : BinaryInteger> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
|
|
// CHECK: br bb6
|
|
|
|
// CHECK: bb6:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
|
|
// CHECK: bb7:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*T to $*Int
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %1 : $*T to $*Int
|
|
// CHECK: %{{.*}} = load %{{.*}} : $*Int
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*T to $*Int
|
|
// CHECK: %{{.*}} = load %{{.*}} : $*Int
|
|
// CHECK: // function_ref specialized divideNum<A>(_:den:)
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize9divideNum_3denxx_xtKSZRzlFSi_Tg5 : $@convention(thin) (Int, Int) -> (Int, @error any Error)
|
|
// CHECK: try_apply %{{.*}}(%{{.*}}, %{{.*}}) : $@convention(thin) (Int, Int) -> (Int, @error any Error), normal bb9, error bb8
|
|
|
|
// CHECK: bb8(%{{.*}} : $any Error):
|
|
// CHECK: br bb4(%{{.*}} : $any Error)
|
|
|
|
// CHECK: bb9(%{{.*}} : $Int):
|
|
// CHECK: store %{{.*}} to %{{.*}} : $*Int
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb6
|
|
|
|
// --- test: multiple void and non-void return values
|
|
|
|
// foo<A> (A) -> Int64
|
|
sil hidden [noinline] [Onone] @$s16eager_specialize3fooys5Int64VxlF : $@convention(thin) <T> (@in T) -> Int64 {
|
|
// %0 // users: %1, %4
|
|
bb0(%0 : $*T):
|
|
%2 = integer_literal $Builtin.Int64, 3
|
|
%3 = struct $Int64 (%2 : $Builtin.Int64)
|
|
destroy_addr %0 : $*T
|
|
return %3 : $Int64
|
|
}
|
|
|
|
// voidReturn<A> (A) -> ()
|
|
sil [_specialize where T == Float] [_specialize where T == Int64] @$s16eager_specialize10voidReturnyyxlF : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
// function_ref foo<A> (A) -> Int64
|
|
%2 = function_ref @$s16eager_specialize3fooys5Int64VxlF : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
%3 = apply %2<T>(%0) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: // specialized voidReturn<A>(_:)
|
|
// CHECK: sil shared @$s16eager_specialize10voidReturnyyxlFSf_Tg5 : $@convention(thin) (Float) -> () {
|
|
// %0 // user: %2
|
|
// CHECK: bb0(%0 : $Float):
|
|
// CHECK: return %5 : $()
|
|
|
|
// CHECK-LABEL: // specialized voidReturn<A>(_:)
|
|
// CHECK: sil shared @$s16eager_specialize10voidReturnyyxlFs5Int64V_Tg5 : $@convention(thin) (Int64) -> () {
|
|
// CHECK: bb0(%0 : $Int64):
|
|
// CHECK: return %5 : $()
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
//
|
|
// CHECK-LABEL: // voidReturn<A>(_:)
|
|
// CHECK: sil @$s16eager_specialize10voidReturnyyxlF : $@convention(thin) <T> (@in T) -> () {
|
|
// CHECK: bb0(%0 : $*T):
|
|
// CHECK: builtin "cmp_eq_Word"
|
|
// CHECK: cond_br %{{.*}}, bb7, bb1
|
|
|
|
// CHECK: bb2:
|
|
// CHECK: builtin "cmp_eq_Word"
|
|
// CHECK: cond_br %{{.*}}, bb6, bb3
|
|
|
|
// CHECK: bb4:
|
|
// CHECK: function_ref @$s16eager_specialize3fooys5Int64VxlF : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
// CHECK: apply %{{.*}}<T>(%0) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
// CHECK: br bb5
|
|
|
|
// CHECK: bb5:
|
|
// CHECK: tuple ()
|
|
// CHECK: return
|
|
|
|
// CHECK: bb6:
|
|
// CHECK: function_ref @$s16eager_specialize10voidReturnyyxlFSf_Tg5 : $@convention(thin) (Float) -> ()
|
|
// CHECK: br bb5
|
|
|
|
// CHECK: bb7:
|
|
// CHECK: br bb5
|
|
|
|
// nonvoidReturn<A>(A) -> Int64
|
|
sil [_specialize where T == Float] [_specialize where T == Int64] @$s16eager_specialize13nonvoidReturnys5Int64VxlF : $@convention(thin) <T> (@in T) -> Int64 {
|
|
// %0 // users: %1, %3
|
|
bb0(%0 : $*T):
|
|
// function_ref foo<A>(A) -> Int64
|
|
%2 = function_ref @$s16eager_specialize3fooys5Int64VxlF : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
%3 = apply %2<T>(%0) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
return %3 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: // specialized nonvoidReturn<A>(_:)
|
|
// CHECK: sil shared @$s16eager_specialize13nonvoidReturnys5Int64VxlFSf_Tg5 : $@convention(thin) (Float) -> Int64 {
|
|
// CHECK: bb0(%0 : $Float):
|
|
// CHECK: return %4 : $Int64
|
|
|
|
// CHECK-LABEL: // specialized nonvoidReturn<A>(_:)
|
|
// CHECK: sil shared @$s16eager_specialize13nonvoidReturnys5Int64VxlFAD_Tg5 : $@convention(thin) (Int64) -> Int64 {
|
|
// CHECK: bb0(%0 : $Int64):
|
|
// CHECK: return %4 : $Int64
|
|
|
|
// CHECK-LABEL: // nonvoidReturn<A>(_:)
|
|
// CHECK: sil @$s16eager_specialize13nonvoidReturnys5Int64VxlF : $@convention(thin) <T> (@in T) -> Int64 {
|
|
// CHECK: bb0(%0 : $*T):
|
|
// CHECK: builtin "cmp_eq_Word"
|
|
// CHECK: cond_br %{{.*}}, bb7, bb1
|
|
|
|
// CHECK: bb1:
|
|
// CHECK: builtin "cmp_eq_Word"
|
|
// CHECK: cond_br %{{.*}}, bb6, bb3
|
|
|
|
// CHECK: bb4:
|
|
// CHECK: // function_ref foo<A>(_:)
|
|
// CHECK: function_ref @$s16eager_specialize3fooys5Int64VxlF : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Int64
|
|
// CHECK: apply %{{.*}}<T>
|
|
// CHECK: br bb5(%{{.*}} : $Int64)
|
|
|
|
// CHECK: bb5(%{{.*}} : $Int64):
|
|
// CHECK: return %{{.*}} : $Int64
|
|
|
|
// CHECK: bb6:
|
|
// CHECK: br bb5(%{{.*}} : $Int64)
|
|
|
|
// CHECK: bb7:
|
|
// CHECK: br bb5(%{{.*}} : $Int64)
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check the ability to specialize for _Trivial(64) and _Trivial(32)
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// copyValueAndReturn<A> (A, s : inout A) -> A
|
|
sil [noinline] [_specialize where S : _Trivial(32)] [_specialize where S : _Trivial(64)] @$s16eager_specialize18copyValueAndReturn_1sxx_xztlF : $@convention(thin) <S> (@in S, @inout S) -> @out S {
|
|
bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
copy_addr %2 to [init] %0 : $*S
|
|
destroy_addr %1 : $*S
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
} // end sil function '$s16eager_specialize18copyValueAndReturn_1sxx_xztlF'
|
|
|
|
|
|
// Check specialized for 32 bits
|
|
// specialized copyValueAndReturn<A>(A, s : inout A) -> A
|
|
// CHECK-LABEL: sil shared [noinline] @$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze31_lIetilr_Tp5 : $@convention(thin) <S where S : _Trivial(32)> (@in S, @inout S) -> @out S
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
// CHECK: copy_addr %2 to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
// CHECK: } // end sil function '$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze31_lIetilr_Tp5'
|
|
|
|
// Check specialized for 64 bits
|
|
// specialized copyValueAndReturn<A>(A, s : inout A) -> A
|
|
// CHECK-LABEL: sil shared [noinline] @$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze63_lIetilr_Tp5 : $@convention(thin) <S where S : _Trivial(64)> (@in S, @inout S) -> @out S
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
// CHECK: copy_addr %2 to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
// CHECK: } // end sil function '$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze63_lIetilr_Tp5'
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
//
|
|
// CHECK-LABEL: sil [noinline] @$s16eager_specialize18copyValueAndReturn_1sxx_xztlF : $@convention(thin) <S> (@in S, @inout S) -> @out S
|
|
// Check if size == 8 bytes, i.e. 64 444its
|
|
// CHECK: %{{.*}} = metatype $@thick S.Type
|
|
// CHECK: %{{.*}} = builtin "sizeof"<S>(%{{.*}} : $@thick S.Type) : $Builtin.Word
|
|
// CHECK: %{{.*}} = integer_literal $Builtin.Word, 8
|
|
// CHECK: %{{.*}} = builtin "cmp_eq_Word"(%{{.*}} : $Builtin.Word, %{{.*}} : $Builtin.Word) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb10, bb1
|
|
|
|
// Check if size == 4 bytes, i.32 2 2 2 bits
|
|
// CHECK: bb1:
|
|
// CHECK: %{{.*}} = metatype $@thick S.Type
|
|
// CHECK: %{{.*}} = builtin "sizeof"<S>(%{{.*}} : $@thick S.Type) : $Builtin.Word
|
|
// CHECK: %{{.*}} = integer_literal $Builtin.Word, 4
|
|
// CHECK: %{{.*}} = builtin "cmp_eq_Word"(%{{.*}} : $Builtin.Word, %{{.*}} : $Builtin.Word) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb8, bb4
|
|
|
|
// None of the constraint checks was successful, perform a generic copy.
|
|
// CHECK: bb6:
|
|
// CHECK: copy_addr %{{.*}} to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: br bb7
|
|
|
|
// CHECK: bb7:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
|
|
// Check if it is a trivial type
|
|
// CHECK: bb8:
|
|
// CHECK: %{{.*}} = builtin "ispod"<S>(%{{.*}} : $@thick S.Type) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb9, bb5
|
|
|
|
// Invoke the specialized function for 32 bits
|
|
// CHECK: bb9:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %1 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*S to $*S
|
|
// function_ref specialized copyValueAndReturn<A> (A, s : inout A) -> A
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze31_lIetilr_Tp5 : $@convention(thin) <τ_0_0 where τ_0_0 : _Trivial(32)> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = apply %{{.*}}<S>(%{{.*}}, %{{.*}}, %{{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : _Trivial(32)> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb7
|
|
|
|
// Check if it is a trivial type
|
|
// CHECK: bb10:
|
|
// CHECK: %{{.*}} = builtin "ispod"<S>(%{{.*}} : $@thick S.Type) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb11, bb2
|
|
|
|
// Invoke the specialized function for 64 bits
|
|
// CHECK: bb11:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %1 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*S to $*S
|
|
// function_ref specialized copyValueAndReturn<A> (A, s : inout A) -> A
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze63_lIetilr_Tp5 : $@convention(thin) <τ_0_0 where τ_0_0 : _Trivial(64)> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = apply %{{.*}}<S>(%{{.*}}, %{{.*}}, %{{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : _Trivial(64)> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb7
|
|
// CHECK: } // end sil function '$s16eager_specialize18copyValueAndReturn_1sxx_xztlF'
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check the ability to specialize for _Trivial
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// copyValueAndReturn2<A> (A, s : inout A) -> A
|
|
sil [noinline] [_specialize where S : _Trivial] @$s16eager_specialize19copyValueAndReturn2_1sxx_xztlF : $@convention(thin) <S> (@in S, @inout S) -> @out S {
|
|
bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
copy_addr %2 to [init] %0 : $*S
|
|
destroy_addr %1 : $*S
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
} // end sil function '$s16eager_specialize19copyValueAndReturn2_1sxx_xztlF'
|
|
|
|
// Check the specialization for _Trivial
|
|
// specialized copyValueAndReturn2<A> (A, s : inout A) -> A
|
|
// CHECK-LABEL: sil shared [noinline] @$s16eager_specialize19copyValueAndReturn2_1sxx_xztlFxxxRlzTlIetilr_Tp5 : $@convention(thin) <S where S : _Trivial> (@in S, @inout S) -> @out S
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
// CHECK: copy_addr %2 to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: %5 = tuple ()
|
|
// CHECK: return %5 : $()
|
|
// CHECK: } // end sil function '$s16eager_specialize19copyValueAndReturn2_1sxx_xztlFxxxRlzTlIetilr_Tp5'
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
// copyValueAndReturn2<A> (A, s : inout A) -> A
|
|
// CHECK-LABEL: sil [noinline] @$s16eager_specialize19copyValueAndReturn2_1sxx_xztlF : $@convention(thin) <S> (@in S, @inout S) -> @out S
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
// CHECK: %3 = metatype $@thick S.Type
|
|
// CHECK: %4 = builtin "ispod"<S>(%3 : $@thick S.Type) : $Builtin.Int1
|
|
// CHECK: cond_br %4, bb4, bb1
|
|
|
|
// None of the constraint checks was successful, perform a generic copy.
|
|
// CHECK: bb2:
|
|
// CHECK: copy_addr %2 to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: br bb3
|
|
|
|
// CHECK: bb3:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
|
|
// Invoke the specialized function for trivial types
|
|
// CHECK: bb4:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %1 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*S to $*S
|
|
// function_ref specialized copyValueAndReturn2<A> (A, s : inout A) -> A
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize19copyValueAndReturn2_1sxx_xztlFxxxRlzTlIetilr_Tp5 : $@convention(thin) <τ_0_0 where τ_0_0 : _Trivial> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = apply %{{.*}}<S>(%{{.*}}, %{{.*}}, %{{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : _Trivial> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb3
|
|
// CHECK: } // end sil function '$s16eager_specialize19copyValueAndReturn2_1sxx_xztlF'
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check the ability to specialize for _RefCountedObject
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// copyValueAndReturn3<A> (A, s : inout A) -> A
|
|
sil [noinline] [_specialize where S : _RefCountedObject] @$s16eager_specialize19copyValueAndReturn3_1sxx_xztlF : $@convention(thin) <S> (@in S, @inout S) -> @out S {
|
|
bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
copy_addr %2 to [init] %0 : $*S
|
|
destroy_addr %1 : $*S
|
|
%7 = tuple ()
|
|
return %7 : $()
|
|
} // end sil function '$s16eager_specialize19copyValueAndReturn3_1sxx_xztlF'
|
|
|
|
|
|
// Check for specialized function for _RefCountedObject
|
|
// specialized copyValueAndReturn3<A> (A, s : inout A) -> A
|
|
// CHECK-LABEL: sil shared [noinline] @$s16eager_specialize19copyValueAndReturn3_1sxx_xztlFxxxRlzRlIetilr_Tp5 : $@convention(thin) <S where S : _RefCountedObject> (@in S, @inout S) -> @out S
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
// CHECK: copy_addr %2 to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: %5 = tuple ()
|
|
// CHECK: return %5 : $()
|
|
// CHECK: } // end sil function '$s16eager_specialize19copyValueAndReturn3_1sxx_xztlFxxxRlzRlIetilr_Tp5'
|
|
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
// copyValueAndReturn3<A> (A, s : inout A) -> A
|
|
// CHECK-LABEL: sil [noinline] @$s16eager_specialize19copyValueAndReturn3_1sxx_xztlF : $@convention(thin) <S> (@in S, @inout S) -> @out S {
|
|
// Check if can be a class
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S, %2 : $*S):
|
|
// CHECK: %3 = metatype $@thick S.Type
|
|
// CHECK: %4 = builtin "canBeClass"<S>(%3 : $@thick S.Type) : $Builtin.Int8
|
|
// CHECK: %5 = integer_literal $Builtin.Int8, 1
|
|
// CHECK: %6 = builtin "cmp_eq_Int8"(%4 : $Builtin.Int8, %5 : $Builtin.Int8) : $Builtin.Int1
|
|
// True if it is a Swift class
|
|
// CHECK: cond_br %6, bb5, bb8
|
|
|
|
// CHECK: bb3:
|
|
// CHECK: copy_addr %2 to [init] %0 : $*S
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: br bb4
|
|
|
|
// CHECK: bb4:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
|
|
// Invoke the specialized function for ref-conted objects
|
|
// CHECK: bb7:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %1 : $*S to $*S
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*S to $*S
|
|
// function_ref specialized copyValueAndReturn3<A> (A, s : inout A) -> A
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize19copyValueAndReturn3_1sxx_xztlFxxxRlzRlIetilr_Tp5 : $@convention(thin) <τ_0_0 where τ_0_0 : _RefCountedObject> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = apply %{{.*}}<S>(%{{.*}}, %{{.*}}, %{{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : _RefCountedObject> (@in τ_0_0, @inout τ_0_0) -> @out τ_0_0
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb4
|
|
|
|
// Check if the object could be of a class or objc existential type
|
|
// CHECK: bb8:
|
|
// CHECK: %{{.*}} = integer_literal $Builtin.Int8, 2
|
|
// CHECK: %{{.*}} = builtin "cmp_eq_Int8"(%{{.*}} : $Builtin.Int8, %{{.*}} : $Builtin.Int8) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb9, bb1
|
|
|
|
// CHECK: bb9:
|
|
// function_ref _swift_isClassOrObjCExistentialType
|
|
// CHECK: %{{.*}} = function_ref @_swift_isClassOrObjCExistentialType : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> Bool
|
|
// CHECK: %{{.*}} = apply %{{.*}}<S>(%{{.*}}) : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> Bool
|
|
// CHECK: %{{.*}} = struct_extract %{{.*}} : $Bool, #Bool._value
|
|
// CHECK: cond_br %{{.*}}, bb6, bb2
|
|
// CHECK: } // end sil function '$s16eager_specialize19copyValueAndReturn3_1sxx_xztlF'
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check the ability to produce exported specializations, which can
|
|
// be referenced from other object files.
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// exportSpecializations<A> (A) -> ()
|
|
sil [_specialize exported: true, where T == Int64] @$s16eager_specialize21exportSpecializationsyyxlF : $@convention(thin) <T> (@in T) -> () {
|
|
bb0(%0 : $*T):
|
|
destroy_addr %0 : $*T
|
|
%3 = tuple ()
|
|
return %3 : $()
|
|
} // end sil function '$s16eager_specialize21exportSpecializationsyyxlF'
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check the ability to produce explicit partial specializations.
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// checkExplicitPartialSpecialization<A, B> (A, B) -> ()
|
|
sil [_specialize kind: partial, where T == Int64] @$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lF : $@convention(thin) <T, S> (@in T, @in S) -> () {
|
|
bb0(%0 : $*T, %1 : $*S):
|
|
destroy_addr %1 : $*S
|
|
destroy_addr %0 : $*T
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
} // end sil function '$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lF'
|
|
|
|
|
|
// Check for specialized function for τ_0_0 == Int64
|
|
// specialized checkExplicitPartialSpecialization<A, B> (A, B) -> ()
|
|
// CHECK-LABEL: sil shared @$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lFs5Int64Vq_ADRszr0_lIetyi_Tp5 : $@convention(thin) <T, S where T == Int64> (Int64, @in S) -> ()
|
|
// CHECK: bb0(%0 : $Int64, %1 : $*S):
|
|
// CHECK: %2 = alloc_stack $Int64
|
|
// CHECK: store %0 to %2 : $*Int64
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: destroy_addr %2 : $*Int64
|
|
// CHECK: %6 = tuple ()
|
|
// CHECK: dealloc_stack %2 : $*Int64
|
|
// CHECK: return %6 : $()
|
|
// CHECK: } // end sil function '$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lFs5Int64Vq_ADRszr0_lIetyi_Tp5'
|
|
|
|
// Generic with specialized dispatch. No more [specialize] attribute.
|
|
// checkExplicitPartialSpecialization<A, B> (A, B) -> ()
|
|
// CHECK-LABEL: sil @$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lF : $@convention(thin) <T, S> (@in T, @in S) -> ()
|
|
// CHECK: bb0(%0 : $*T, %1 : $*S):
|
|
// CHECK: %2 = metatype $@thick T.Type
|
|
// CHECK: %3 = metatype $@thick Int64.Type
|
|
// CHECK: %4 = unchecked_bitwise_cast %2 : $@thick T.Type to $Builtin.Word
|
|
// CHECK: %5 = unchecked_bitwise_cast %3 : $@thick Int64.Type to $Builtin.Word
|
|
// CHECK: %6 = builtin "cmp_eq_Word"(%4 : $Builtin.Word, %5 : $Builtin.Word) : $Builtin.Int1
|
|
// CHECK: cond_br %6, bb4, bb1
|
|
|
|
// Type dispatch was not successful.
|
|
// CHECK: bb2:
|
|
// CHECK: destroy_addr %1 : $*S
|
|
// CHECK: destroy_addr %0 : $*T
|
|
// CHECK: br bb3
|
|
|
|
// CHECK: bb3:
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: return %{{.*}} : $()
|
|
|
|
// Invoke a partially specialized function.
|
|
// CHECK: bb4:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %0 : $*T to $*Int64
|
|
// CHECK: %{{.*}} = load %{{.*}} : $*Int64
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %1 : $*S to $*S
|
|
// function_ref specialized checkExplicitPartialSpecialization<A, B> (A, B) -> ()
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lFs5Int64Vq_ADRszr0_lIetyi_Tp5 : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 == Int64> (Int64, @in τ_0_1) -> ()
|
|
// CHECK: %{{.*}} = apply %{{.*}}<Int64, S>(%{{.*}}, %{{.*}}) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 == Int64> (Int64, @in τ_0_1) -> ()
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $() to $()
|
|
// CHECK: br bb3
|
|
// CHECK: } // end sil function '$s16eager_specialize34checkExplicitPartialSpecializationyyx_q_tr0_lF'
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Check that functions with unreachable instructions can be specialized.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
protocol P {
|
|
}
|
|
|
|
struct T : P {
|
|
init()
|
|
}
|
|
|
|
extension P {
|
|
public static func f(_ x: Self) -> Self
|
|
}
|
|
|
|
sil @error : $@convention(thin) () -> Never
|
|
|
|
// CHECK-LABEL: sil @$s16eager_specialize1PPAAE1fyxxFZ : $@convention(method) <Self where Self : P> (@in Self, @thick Self.Type) -> @out Self
|
|
// CHECK: %{{.*}} = metatype $@thick Self.Type
|
|
// CHECK: %{{.*}} = metatype $@thick T.Type
|
|
// CHECK: %{{.*}} = unchecked_bitwise_cast %{{.*}} : $@thick Self.Type to $Builtin.Word
|
|
// CHECK: %{{.*}} = unchecked_bitwise_cast %{{.*}} : $@thick T.Type to $Builtin.Word
|
|
// CHECK: %{{.*}} = builtin "cmp_eq_Word"(%{{.*}} : $Builtin.Word, %{{.*}} : $Builtin.Word) : $Builtin.Int1
|
|
// CHECK: cond_br %{{.*}}, bb3, bb1
|
|
|
|
// CHECK: bb2:
|
|
// CHECK: %{{.*}} = function_ref @error : $@convention(thin) () -> Never
|
|
// CHECK: %{{.*}} = apply %{{.*}}() : $@convention(thin) () -> Never
|
|
// CHECK: unreachable
|
|
|
|
// CHECK: bb3:
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %{{.*}} : $*Self to $*T
|
|
// CHECK: %{{.*}} = unchecked_addr_cast %{{.*}} : $*Self to $*T
|
|
// CHECK: %{{.*}} = load %{{.*}} : $*T
|
|
// CHECK: %{{.*}} = unchecked_trivial_bit_cast %{{.*}} : $@thick Self.Type to $@thick T.Type
|
|
// CHECK: %{{.*}} = function_ref @$s16eager_specialize1PPAAE1fyxxFZ4main1TV_Tg5 : $@convention(method) (T, @thick T.Type) -> T
|
|
// CHECK: %{{.*}} = apply %{{.*}}(%{{.*}}, %{{.*}}) : $@convention(method) (T, @thick T.Type) -> T
|
|
// CHECK: store %{{.*}} to %{{.*}} : $*T
|
|
// CHECK: %{{.*}} = tuple ()
|
|
// CHECK: unreachable
|
|
// CHECK: } // end sil function '$s16eager_specialize1PPAAE1fyxxFZ'
|
|
|
|
sil [_specialize exported: false, kind: full, where Self == T] @$s16eager_specialize1PPAAE1fyxxFZ : $@convention(method) <Self where Self : P> (@in Self, @thick Self.Type) -> @out Self {
|
|
bb0(%0 : $*Self, %1 : $*Self, %2 : $@thick Self.Type):
|
|
// function_ref error
|
|
%5 = function_ref @error : $@convention(thin) () -> Never
|
|
%6 = apply %5() : $@convention(thin) () -> Never
|
|
unreachable
|
|
} // end sil function '$s16eager_specialize1PPAAE1fyxxFZ'
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check that IRGen generates efficient code for fixed-size Trivial
|
|
// constraints.
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Check that a specialization for _Trivial(32) uses direct loads and stores
|
|
// instead of value witness functions to load and store the value of a generic type.
|
|
// CHECK-IRGEN-LABEL: define linkonce_odr hidden swiftcc void @"$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze31_lIetilr_Tp5"(ptr noalias sret(i32) captures(none) %0, ptr noalias captures(none) dereferenceable(4) %1, ptr captures(none) dereferenceable(4) %2, ptr %S
|
|
// CHECK-IRGEN: entry:
|
|
// CHECK-IRGEN: %3 = load i32, ptr %2
|
|
// CHECK-IRGEN-NEXT: store i32 %3, ptr %0
|
|
// CHECK-IRGEN-NEXT: ret void
|
|
// CHECK-IRGEN-NEXT:}
|
|
|
|
// Check that a specialization for _Trivial(64) uses direct loads and stores
|
|
// instead of value witness functions to load and store the value of a generic type.
|
|
// CHECK-IRGEN-LABEL: define linkonce_odr hidden swiftcc void @"$s16eager_specialize18copyValueAndReturn_1sxx_xztlFxxxRlze63_lIetilr_Tp5"(ptr noalias sret(i64) captures(none) %0, ptr noalias captures(none) dereferenceable(8) %1, ptr captures(none) dereferenceable(8) %2, ptr %S
|
|
// CHECK-IRGEN: entry:
|
|
// CHECK-IRGEN: %3 = load i64, ptr %2
|
|
// CHECK-IRGEN-NEXT: store i64 %3, ptr %0
|
|
// CHECK-IRGEN-NEXT: ret void
|
|
// CHECK-IRGEN-NEXT: }
|
|
|
|
// Check that a specialization for _Trivial does not call the 'destroy' value witness,
|
|
// because it is known that the object is Trivial, i.e. contains no references.
|
|
// CHECK-IRGEN-LABEL: define linkonce_odr hidden swiftcc void @"$s16eager_specialize19copyValueAndReturn2_1sxx_xztlFxxxRlzTlIetilr_Tp5"(ptr noalias sret(%swift.opaque) %0, ptr noalias %1, ptr %2, ptr %S
|
|
// CHECK-IRGEN-NEXT: entry:
|
|
// CHECK-IRGEN: %3 = getelementptr inbounds ptr, ptr %S, i{{.*}} -1
|
|
// CHECK-IRGEN-NEXT: %S.valueWitnesses = load ptr, ptr %3
|
|
// CHECK-IRGEN-NEXT: %4 = getelementptr inbounds ptr, ptr %S.valueWitnesses
|
|
// CHECK-IRGEN-NEXT: %InitializeWithCopy = load ptr, ptr %4
|
|
// CHECK-IRGEN-arm64e-NEXT: ptrtoint ptr %4 to i64
|
|
// CHECK-IRGEN-arm64e-NEXT: call i64 @llvm.ptrauth.blend.i64
|
|
// CHECK-IRGEN-NEXT: call {{.*}} %InitializeWithCopy
|
|
// CHECK-IRGEN-NEXT: ret void
|
|
// CHECK-IRGEN-NEXT: }
|
|
|
|
// Check that a specialization for _RefCountedObject just copies the fixed-size reference,
|
|
// and call retain/release directly, instead of calling the value witness functions.
|
|
// The matching patterns in this test are rather non-precise to cover both objc and non-objc platforms.
|
|
// CHECK-IRGEN-LABEL: define{{.*}}@"$s16eager_specialize19copyValueAndReturn3_1sxx_xztlFxxxRlzRlIetilr_Tp5"
|
|
// CHECK-IRGEN: entry:
|
|
// CHECK-IRGEN-NOT: ret void
|
|
// CHECK-IRGEN: call {{.*}}etain
|
|
// CHECK-IRGEN-NOT: ret void
|
|
// CHECK-IRGEN: call {{.*}}elease
|
|
// CHECK-IRGEN: ret void
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Check that try_apply instructions are handled correctly by the
|
|
// eager specializer.
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
protocol ThrowingP {
|
|
func action() throws -> Int64
|
|
}
|
|
|
|
extension Int64 : ThrowingP {
|
|
public func action() throws -> Int64
|
|
}
|
|
|
|
class ClassUsingThrowingP {
|
|
required init()
|
|
@_specialize(exported: false, kind: full, where T == Int64)
|
|
public static func f<T>(_: T) throws -> Self where T : ThrowingP
|
|
@_specialize(exported: false, kind: full, where T == Int64)
|
|
public static func g<T>(_ t: T) throws -> Int64 where T : ThrowingP
|
|
deinit
|
|
}
|
|
|
|
// Int64.action()
|
|
sil @$ss5Int64V34eager_specialize_throwing_functionE6actionAByKF : $@convention(method) (Int64) -> (Int64, @error any Error)
|
|
|
|
// protocol witness for ThrowingP.action() in conformance Int64
|
|
sil @$ss5Int64V34eager_specialize_throwing_function9ThrowingPA2cDP6actionAByKFTW : $@convention(witness_method: ThrowingP) (@in_guaranteed Int64) -> (Int64, @error any Error)
|
|
|
|
sil @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfc : $@convention(method) (@owned ClassUsingThrowingP) -> @owned ClassUsingThrowingP
|
|
|
|
sil @$s34eager_specialize_throwing_function19ClassUsingThrowingPCfd : $@convention(method) (@guaranteed ClassUsingThrowingP) -> @owned Builtin.NativeObject
|
|
|
|
// ClassUsingThrowingP.__allocating_init()
|
|
sil @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfC : $@convention(method) (@thick ClassUsingThrowingP.Type) -> @owned ClassUsingThrowingP
|
|
|
|
// ClassUsingThrowingP.__deallocating_deinit
|
|
sil @$s34eager_specialize_throwing_function19ClassUsingThrowingPCfD : $@convention(method) (@owned ClassUsingThrowingP) -> ()
|
|
|
|
// f is a function that may throw according to its type, but does not actually do it.
|
|
// Check that this function is properly specialized by the eager specializer.
|
|
// It should dispatch to its specialized version, but use apply [nothrow] to invoke
|
|
// the specialized version.
|
|
|
|
// CHECK-LABEL: sil @$s34eager_specialize_throwing_function19ClassUsingThrowingPC1fyACXDxKAA0G1PRzlFZ : $@convention(method) <T where T : ThrowingP> (@in T, @thick ClassUsingThrowingP.Type) -> (@owned ClassUsingThrowingP, @error any Error)
|
|
// CHECK: [[SPECIALIZED:%.*]] = function_ref @$s34eager_specialize_throwing_function19ClassUsingThrowingPC1fyACXDxKAA0G1PRzlFZs5Int64V_Tg5 : $@convention(method) (Int64, @thick ClassUsingThrowingP.Type) -> (@owned ClassUsingThrowingP, @error any Error)
|
|
// CHECK: apply [nothrow] [[SPECIALIZED]]
|
|
// CHECK: // end sil function '$s34eager_specialize_throwing_function19ClassUsingThrowingPC1fyACXDxKAA0G1PRzlFZ'
|
|
// static ClassUsingThrowingP.f<A>(_:)
|
|
sil [_specialize exported: false, kind: full, where T == Int64] @$s34eager_specialize_throwing_function19ClassUsingThrowingPC1fyACXDxKAA0G1PRzlFZ : $@convention(method) <T where T : ThrowingP> (@in T, @thick ClassUsingThrowingP.Type) -> (@owned ClassUsingThrowingP, @error any Error) {
|
|
bb0(%0 : $*T, %1 : $@thick ClassUsingThrowingP.Type):
|
|
destroy_addr %0 : $*T
|
|
%4 = unchecked_trivial_bit_cast %1 : $@thick ClassUsingThrowingP.Type to $@thick @dynamic_self ClassUsingThrowingP.Type
|
|
// function_ref ClassUsingThrowingP.__allocating_init()
|
|
%7 = function_ref @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfC : $@convention(method) (@thick ClassUsingThrowingP.Type) -> @owned ClassUsingThrowingP
|
|
%8 = upcast %4 : $@thick @dynamic_self ClassUsingThrowingP.Type to $@thick ClassUsingThrowingP.Type
|
|
%9 = apply %7(%8) : $@convention(method) (@thick ClassUsingThrowingP.Type) -> @owned ClassUsingThrowingP
|
|
%10 = unchecked_ref_cast %9 : $ClassUsingThrowingP to $ClassUsingThrowingP
|
|
return %10 : $ClassUsingThrowingP
|
|
} // end sil function '$s34eager_specialize_throwing_function19ClassUsingThrowingPC1fyACXDxKAA0G1PRzlFZ'
|
|
|
|
// g is a function that may throw according to its type and has a try_apply inside
|
|
// its body.
|
|
// Check that this function is properly specialized by the eager specializer.
|
|
// It should dispatch to its specialized version and use try_apply to invoke
|
|
// the specialized version.
|
|
|
|
// CHECK-LABEL: sil @$s34eager_specialize_throwing_function19ClassUsingThrowingPC1gys5Int64VxKAA0G1PRzlFZ : $@convention(method) <T where T : ThrowingP> (@in T, @thick ClassUsingThrowingP.Type) -> (Int64, @error any Error)
|
|
// CHECK: [[SPECIALIZED:%.*]] = function_ref @$s34eager_specialize_throwing_function19ClassUsingThrowingPC1gys5Int64VxKAA0G1PRzlFZAF_Tg5 : $@convention(method) (Int64, @thick ClassUsingThrowingP.Type) -> (Int64, @error any Error)
|
|
// CHECK: try_apply [[SPECIALIZED]]
|
|
// CHECK: // end sil function '$s34eager_specialize_throwing_function19ClassUsingThrowingPC1gys5Int64VxKAA0G1PRzlFZ'
|
|
|
|
// static ClassUsingThrowingP.g<A>(_:)
|
|
sil [_specialize exported: false, kind: full, where T == Int64] @$s34eager_specialize_throwing_function19ClassUsingThrowingPC1gys5Int64VxKAA0G1PRzlFZ : $@convention(method) <T where T : ThrowingP> (@in T, @thick ClassUsingThrowingP.Type) -> (Int64, @error any Error) {
|
|
bb0(%0 : $*T, %1 : $@thick ClassUsingThrowingP.Type):
|
|
%5 = witness_method $T, #ThrowingP.action : <Self where Self : ThrowingP> (Self) -> () throws -> Int64 : $@convention(witness_method: ThrowingP) <τ_0_0 where τ_0_0 : ThrowingP> (@in_guaranteed τ_0_0) -> (Int64, @error any Error)
|
|
try_apply %5<T>(%0) : $@convention(witness_method: ThrowingP) <τ_0_0 where τ_0_0 : ThrowingP> (@in_guaranteed τ_0_0) -> (Int64, @error any Error), normal bb1, error bb2
|
|
|
|
bb1(%7 : $Int64): // Preds: bb0
|
|
destroy_addr %0 : $*T
|
|
return %7 : $Int64
|
|
|
|
bb2(%10 : $Error): // Preds: bb0
|
|
destroy_addr %0 : $*T
|
|
throw %10 : $Error
|
|
} // end sil function '$s34eager_specialize_throwing_function19ClassUsingThrowingPC1gys5Int64VxKAA0G1PRzlFZ'
|
|
|
|
// Check that a specialization was produced and it is not inlined.
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE-LABEL: sil{{.*}}@{{.*}}testSimpleGeneric{{.*}}where T : _Trivial(64, 64)
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE-LABEL: sil{{.*}}@testSimpleGeneric :
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: [[METATYPE:%.*]] = metatype $@thick T.Type
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: [[SIZEOF:%.*]] = builtin "sizeof"<T>([[METATYPE]] : $@thick T.Type)
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: [[SIZE:%.*]] = integer_literal $Builtin.Word, 8
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: builtin "cmp_eq_Word"([[SIZEOF]] : $Builtin.Word, [[SIZE]] : $Builtin.Word)
|
|
// Invoke the specialization, but do not inline it!
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: function_ref @{{.*}}testSimpleGeneric{{.*}}
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: apply
|
|
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: // end sil function 'testSimpleGeneric'
|
|
|
|
sil [_specialize exported: false, kind: full, where T: _Trivial(64, 64)] @testSimpleGeneric : $@convention(thin) <T>(@in T) -> Builtin.Int64 {
|
|
bb0(%0 : $*T):
|
|
%1 = metatype $@thick T.Type
|
|
%2 = builtin "sizeof"<T>(%1 : $@thick T.Type) : $Builtin.Word
|
|
%8 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
|
|
destroy_addr %0 : $*T
|
|
return %8 : $Builtin.Int64
|
|
}
|
|
|
|
// Don't specialize `shared` definitions they are imported from another module.
|
|
// CHECK-NOT: sil @$s24testDontSpecializeSharedSi_Ts5
|
|
sil shared [_specialize exported: true, kind: full, where T == Int] @testDontSpecializeShared : $@convention(thin) <T>(@in T) -> () {
|
|
bb(%0: $*T):
|
|
destroy_addr %0 : $*T
|
|
%t = tuple()
|
|
return %t : $()
|
|
}
|
|
|
|
// But do specialize `shared` definitions when they are target from another // function.
|
|
// CHECK: sil @$s24testDontSpecializeSharedSd_Ts5
|
|
sil shared [_specialize exported: true, kind: full, target: "testDontSpecializeShared" ,where T == Double] @butSpecializeWhenTargetIsPresent : $@convention(thin) <T>(@in T) -> () {
|
|
bb(%0: $*T):
|
|
destroy_addr %0 : $*T
|
|
%t = tuple()
|
|
return %t : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @testReturnBlockWithArgument
|
|
// CHECK: [[BB1:bb[0-9]+]](%{{.*}} : $Optional<()>):
|
|
// CHECK-NEXT: br [[BBRET:bb[0-9]+]]
|
|
// CHECK: [[BBRET]]:
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'testReturnBlockWithArgument'
|
|
sil [_specialize exported: false, kind: full, where T == S] [ossa] @testReturnBlockWithArgument : $@convention(thin) <T> (@thick T.Type) -> () {
|
|
bb0(%0 : $@thick T.Type):
|
|
%41 = enum $Optional<()>, #Optional.none!enumelt
|
|
br bb4(%41 : $Optional<()>)
|
|
|
|
bb4(%37 : $Optional<()>):
|
|
%38 = tuple ()
|
|
return %38 : $()
|
|
}
|
|
|
|
sil_vtable ClassUsingThrowingP {
|
|
#ClassUsingThrowingP.init!allocator: (ClassUsingThrowingP.Type) -> () -> ClassUsingThrowingP : @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfC // ClassUsingThrowingP.__allocating_init()
|
|
#ClassUsingThrowingP.init!initializer: (ClassUsingThrowingP.Type) -> () -> ClassUsingThrowingP : @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfc // ClassUsingThrowingP.init()
|
|
#ClassUsingThrowingP.deinit!deallocator: @$s34eager_specialize_throwing_function19ClassUsingThrowingPCfD // ClassUsingThrowingP.__deallocating_deinit
|
|
}
|
|
|
|
sil_witness_table hidden Int64: ThrowingP module eager_specialize_throwing_function {
|
|
method #ThrowingP.action: <Self where Self : ThrowingP> (Self) -> () throws -> Int64 : @$ss5Int64V34eager_specialize_throwing_function9ThrowingPA2cDP6actionAByKFTW // protocol witness for ThrowingP.action() in conformance Int64
|
|
}
|
|
|
|
sil_default_witness_table hidden ThrowingP {
|
|
no_default
|
|
}
|