| // RUN: %target-sil-opt -enable-sil-verify-all %s -inline -sil-inline-generics=true -sil-print-generic-specialization-info | %FileCheck %s |
| // RUN: %target-sil-opt -enable-sil-verify-all %s -inline -sil-inline-generics=false | %FileCheck --check-prefix=DISABLED-GENERIC-INLINING-CHECK %s |
| // RUN: %target-swift-frontend -O -emit-ir %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' |
| |
| // 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 |
| } |
| |
| protocol SomeProto : class {} |
| protocol OtherProto {} |
| |
| class MyObject {} |
| extension MyObject : OtherProto {} |
| |
| class MyNumber : MyObject {} |
| extension MyNumber : SomeProto {} |
| |
| sil_vtable MyObject {} |
| sil_vtable MyNumber {} |
| |
| // Make sure we subsitute the correct conformance when inlining. When |
| // substituting we need to pick up the normal_conformance. |
| |
| // CHECK-LABEL: sil @test_inlining : $@convention(objc_method) (@owned MyNumber) -> () { |
| // CHECK-NOT: Generic specialization information for call-site dootherstuff <MyNumber & SomeProto> conformances <(abstract_conformance protocol=OtherProto)> |
| // CHECK: Generic specialization information |
| // CHECK: (normal_conformance type=MyObject protocol=OtherProto) |
| // CHECK: end sil function 'test_inlining' |
| |
| sil @test_inlining : $@convention(objc_method) (@owned MyNumber) -> () { |
| bb0(%0 : $MyNumber): |
| %12 = init_existential_ref %0 : $MyNumber : $MyNumber, $MyNumber & SomeProto |
| %14 = open_existential_ref %12 : $MyNumber & SomeProto to $@opened("B9711AE4-946E-11EA-A871-ACDE48001122") MyNumber & SomeProto |
| %15 = alloc_stack $OtherProto |
| %16 = init_existential_addr %15 : $*OtherProto, $@opened("B9711AE4-946E-11EA-A871-ACDE48001122") MyNumber & SomeProto |
| store %14 to %16 : $*@opened("B9711AE4-946E-11EA-A871-ACDE48001122") MyNumber & SomeProto |
| %18 = function_ref @doStuff : $@convention(thin) <τ_0_0 where τ_0_0 : OtherProto> (@in_guaranteed τ_0_0) -> () |
| %20 = apply %18<@opened("B9711AE4-946E-11EA-A871-ACDE48001122") MyNumber & SomeProto>(%16) : $@convention(thin) <τ_0_0 where τ_0_0 : OtherProto> (@in_guaranteed τ_0_0) -> () |
| destroy_addr %15 : $*OtherProto |
| dealloc_stack %15 : $*OtherProto |
| %27 = tuple () |
| return %27 : $() |
| } |
| |
| sil @dootherstuff : $@convention(thin) <τ_0_0 where τ_0_0 : OtherProto> (@in_guaranteed τ_0_0) -> () |
| |
| sil shared [signature_optimized_thunk] [always_inline] @doStuff : $@convention(thin) <τ_0_0 where τ_0_0 : OtherProto> (@in_guaranteed τ_0_0) -> () { |
| bb0(%0 : $*τ_0_0): |
| %2 = function_ref @dootherstuff : $@convention(thin) <τ_0_0 where τ_0_0 : OtherProto> (@in_guaranteed τ_0_0) -> () |
| %3 = apply %2<τ_0_0>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : OtherProto> (@in_guaranteed τ_0_0) -> () |
| return %3 : $() |
| } |