| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-inline-generics=true | %FileCheck %s |
| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-inline-generics=false | %FileCheck --check-prefix=DISABLED-GENERIC-INLINING-CHECK %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| public func genericFoo<T>(_ t: T) -> T |
| |
| public func testInliningOfGenerics<T>(_ t: T) -> T |
| |
| public protocol P : class { |
| func getSelf() -> Self |
| } |
| |
| extension P { |
| func combine<T>(first: T) -> (T) -> Bool |
| } |
| |
| public func callClosure<T>(arg: P) -> (T) -> Bool where T : P |
| |
| sil @genericFoo : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| copy_addr [take] %1 to [initialization] %0 : $*T |
| %4 = tuple () |
| return %4 : $() |
| } // end sil function 'genericFoo' |
| |
| |
| // Check that the generic call was inlined. |
| // CHECK-LABEL: sil @testInliningOfGenerics |
| // CHECK-NOT: apply |
| // CHECK: end sil function 'testInliningOfGenerics' |
| sil @testInliningOfGenerics : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| // function_ref genericFoo<A> (A) -> A |
| %3 = function_ref @genericFoo : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| %4 = alloc_stack $T |
| copy_addr %1 to [initialization] %4 : $*T |
| %6 = apply %3<T>(%0, %4) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| dealloc_stack %4 : $*T |
| destroy_addr %1 : $*T |
| %9 = tuple () |
| return %9 : $() |
| } // end sil function 'testInliningOfGenerics' |
| |
| sil hidden @P_combine : $@convention(method) <Self where Self : P><T> (@in T, @guaranteed Self) -> @owned @callee_owned (@in T) -> Bool { |
| bb0(%0 : $*T, %1 : $Self): |
| // function_ref P.(combine<A> (first : A1) -> (A1) -> Bool).(closure #1) |
| %4 = function_ref @_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb : $@convention(thin) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0) -> Bool |
| %5 = partial_apply %4<Self, T>() : $@convention(thin) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0) -> Bool |
| destroy_addr %0 : $*T |
| return %5 : $@callee_owned (@in T) -> Bool |
| } // end sil function 'P_combine' |
| |
| // P.(combine<A> (first : A1) -> (A1) -> Bool).(closure #1) |
| sil shared @_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb : $@convention(thin) <Self where Self : P><T> (@in T) -> Bool { |
| bb0(%0 : $*T): |
| %2 = integer_literal $Builtin.Int1, -1 |
| %3 = struct $Bool (%2 : $Builtin.Int1) |
| destroy_addr %0 : $*T |
| return %3 : $Bool |
| } // end sil function '_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb' |
| |
| |
| // Check that P_combine is not inlined into the generic function, because |
| // doing so would result in a partial_apply instruction, with an opened existential |
| // in the substitution list. And this cannot be handled by the IRGen yet. |
| // CHECK-LABEL: sil @dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list |
| // CHECK: [[FUN_REF:%[0-9]+]] = function_ref @P_combine |
| // CHECK: apply [[FUN_REF]] |
| // CHECK: end sil function 'dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list' |
| sil @dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list : $@convention(thin) <T where T : P> (@owned P) -> @owned @callee_owned (@owned T) -> Bool { |
| bb0(%0 : $P): |
| %2 = open_existential_ref %0 : $P to $@opened("41B148C8-F49C-11E6-BE69-A45E60E99281") P |
| // function_ref P.combine<A> (first : A1) -> (A1) -> Bool |
| %3 = function_ref @P_combine : $@convention(method) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0, @guaranteed τ_0_0) -> @owned @callee_owned (@in τ_1_0) -> Bool |
| %4 = open_existential_ref %0 : $P to $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P |
| %5 = witness_method $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P, #P.getSelf!1 : <Self where Self : P> (Self) -> () -> @dynamic_self Self, %4 : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0 |
| %6 = apply %5<@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P>(%4) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0 |
| %7 = init_existential_ref %6 : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P, $P |
| %8 = alloc_stack $P |
| store %7 to %8 : $*P |
| %10 = apply %3<@opened("41B148C8-F49C-11E6-BE69-A45E60E99281") P, P>(%8, %2) : $@convention(method) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0, @guaranteed τ_0_0) -> @owned @callee_owned (@in τ_1_0) -> Bool |
| // function_ref thunk |
| %11 = function_ref @thunk1 : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool |
| %12 = partial_apply %11(%10) : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool |
| // function_ref thunk |
| %13 = function_ref @thunk2 : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0, @owned @callee_owned (@owned P) -> Bool) -> Bool |
| %14 = partial_apply %13<T>(%12) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0, @owned @callee_owned (@owned P) -> Bool) -> Bool |
| dealloc_stack %8 : $*P |
| strong_release %0 : $P |
| return %14 : $@callee_owned (@owned T) -> Bool |
| } // end sil function 'dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list' |
| |
| // thunk |
| sil shared [transparent] [reabstraction_thunk] @thunk1 : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool { |
| bb0(%0 : $P, %1 : $@callee_owned (@in P) -> Bool): |
| %2 = alloc_stack $P |
| store %0 to %2 : $*P |
| %4 = apply %1(%2) : $@callee_owned (@in P) -> Bool |
| dealloc_stack %2 : $*P |
| return %4 : $Bool |
| } // end sil function 'thunk1' |
| |
| // thunk |
| sil shared [transparent] [reabstraction_thunk] @thunk2 : $@convention(thin) <T where T : P> (@owned T, @owned @callee_owned (@owned P) -> Bool) -> Bool { |
| bb0(%0 : $T, %1 : $@callee_owned (@owned P) -> Bool): |
| %2 = init_existential_ref %0 : $T : $T, $P |
| %3 = apply %1(%2) : $@callee_owned (@owned P) -> Bool |
| return %3 : $Bool |
| } // end sil function 'thunk2' |
| |
| |
| sil [always_inline] @alwaysInlineGenericCallee : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| copy_addr [take] %1 to [initialization] %0 : $*T |
| %4 = tuple () |
| return %4 : $() |
| } // end sil function 'alwaysInlineGenericCallee' |
| |
| sil [transparent] @transparentGenericCallee : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| copy_addr [take] %1 to [initialization] %0 : $*T |
| %4 = tuple () |
| return %4 : $() |
| } // end sil function 'transparentInlineGenericCallee' |
| |
| |
| // Check that [always_inline] and [transparent] functions are inlined even if |
| // inlining of generics is disabled. Regular generic functions should not be |
| // inlined. |
| // DISABLED-GENERIC-INLINING-CHECK-LABEL: sil @testComplexInliningOfGenerics |
| // DISABLED-GENERIC-INLINING-CHECK-NOT: function_ref @{{.*}} |
| // DISABLED-GENERIC-INLINING-CHECK-NOT: apply |
| // DISABLED-GENERIC-INLINING-CHECK: [[FUNC:%[0-9]+]] = function_ref @genericFoo |
| // DISABLED-GENERIC-INLINING-CHECK: apply [[FUNC]] |
| // DISABLED-GENERIC-INLINING-CHECK-NOT: function_ref |
| // DISABLED-GENERIC-INLINING-CHECK-NOT: apply |
| // DISABLED-GENERIC-INLINING-CHECK: end sil function 'testComplexInliningOfGenerics' |
| |
| // Check that all callees are inlined if inlining of generics is enabled. |
| // CHECK-LABEL: sil @testComplexInliningOfGenerics |
| // CHECK-NOT: apply |
| // CHECK: end sil function 'testComplexInliningOfGenerics' |
| sil @testComplexInliningOfGenerics : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| |
| // Call an [always_inline] function. |
| %3 = function_ref @alwaysInlineGenericCallee : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| %4 = alloc_stack $T |
| copy_addr %1 to [initialization] %4 : $*T |
| %6 = apply %3<T>(%0, %4) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| dealloc_stack %4 : $*T |
| |
| // Call a [transparent] function. |
| %8 = function_ref @transparentGenericCallee : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| %9 = alloc_stack $T |
| copy_addr %1 to [initialization] %9 : $*T |
| %10 = apply %8<T>(%0, %9) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| dealloc_stack %9 : $*T |
| |
| // Call a regular function. |
| // function_ref genericFoo<A> (A) -> A |
| %12 = function_ref @genericFoo : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| %13 = alloc_stack $T |
| copy_addr %1 to [initialization] %13 : $*T |
| %15 = apply %12<T>(%0, %13) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 |
| dealloc_stack %13 : $*T |
| |
| destroy_addr %1 : $*T |
| %18 = tuple () |
| return %18 : $() |
| } // end sil function 'testComplexInliningOfGenerics' |
| |
| sil_default_witness_table P { |
| no_default |
| } |