// 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 public func testInliningOfGenerics(_ t: T) -> T public protocol P : class { func getSelf() -> Self } extension P { func combine(first: T) -> (T) -> Bool } public func callClosure(arg: P) -> (T) -> Bool where T : P sil @genericFoo : $@convention(thin) (@in T) -> @out T { bb0(%0 : $*T, %1 : $*T): copy_addr [take] %1 to [init] %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) (@in T) -> @out T { bb0(%0 : $*T, %1 : $*T): // function_ref genericFoo (A) -> A %3 = function_ref @genericFoo : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 %4 = alloc_stack $T copy_addr %1 to [init] %4 : $*T %6 = apply %3(%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) (@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) (@in T) -> @out T { bb0(%0 : $*T, %1 : $*T): copy_addr [take] %1 to [init] %0 : $*T %4 = tuple () return %4 : $() } // end sil function 'alwaysInlineGenericCallee' sil [transparent] @transparentGenericCallee : $@convention(thin) (@in T) -> @out T { bb0(%0 : $*T, %1 : $*T): copy_addr [take] %1 to [init] %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) (@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 [init] %4 : $*T %6 = apply %3(%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 [init] %9 : $*T %10 = apply %8(%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 %12 = function_ref @genericFoo : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0 %13 = alloc_stack $T copy_addr %1 to [init] %13 : $*T %15 = apply %12(%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 substitute 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 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) Self %15 = alloc_stack $OtherProto %16 = init_existential_addr %15 : $*OtherProto, $@opened("B9711AE4-946E-11EA-A871-ACDE48001122", MyNumber & SomeProto) Self store %14 to %16 : $*@opened("B9711AE4-946E-11EA-A871-ACDE48001122", MyNumber & SomeProto) Self %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) Self>(%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 : $() }