// RUN: %target-sil-opt -sil-print-types -parse-serialized-sil -enable-sil-verify-all -sil-partial-specialization -generic-specializer -save-optimization-record-path=%t.yaml %/s | %FileCheck %s // RUN: %FileCheck -check-prefix=YAML %s < %t.yaml sil_stage canonical import Builtin import Swift // CHECK-LABEL: sil @exp1 : $@convention(thin) () -> () { // CHECK-NOT: apply // Call of specialized initializer: // CHECK: [[CTOR:%[0-9]+]] = function_ref @$s8XXX_inits5Int32V_Tt1g5 // CHECK: apply [[CTOR]] // CHECK: [[ACCEPTS_INT:%[0-9]+]] = function_ref @acceptsInt // Call of specialized XXX_foo: // CHECK: [[FOO:%[0-9]+]] = function_ref @$s7XXX_foos5Int32V_Tg5 // CHECK: apply [[FOO]] // CHECK: apply [[ACCEPTS_INT]] // CHECK: return // CHEcK: sil @exp2 : $@convention(thin) () -> () { // YAML: --- !Passed // YAML-NEXT: Pass: sil-generic-specializer // YAML-NEXT: Name: sil.Specialized // YAML-NEXT: DebugLoc: // YAML: File: {{.*}}/specialize.sil // YAML: Line: 132 // YAML: Column: 8 // YAML-NEXT: Function: exp1 // YAML-NEXT: Args: // YAML-NEXT: - String: 'Specialized function ' // YAML-NEXT: - Function: '"XXX_init"' // YAML-NEXT: DebugLoc: // YAML: File: {{.*}}/specialize.sil // YAML: Line: 73 // YAML: Column: 17 // YAML-NEXT: - String: ' with type ' // YAML-NEXT: - FuncType: '(Int32) -> XXX' // YAML-NEXT: ... // YAML-NEXT: --- !Passed // YAML-NEXT: Pass: sil-generic-specializer // YAML-NEXT: Name: sil.Specialized // YAML-NEXT: DebugLoc: // YAML: File: {{.*}}/specialize.sil // YAML: Line: 142 // YAML: Column: 9 // YAML-NEXT: Function: exp1 // YAML-NEXT: Args: // YAML-NEXT: - String: 'Specialized function ' // YAML-NEXT: - Function: '"XXX_foo"' // YAML-NEXT: DebugLoc: // YAML: File: {{.*}}/specialize.sil // YAML: Line: 90 // YAML: Column: 17 // YAML-NEXT: - String: ' with type ' // YAML-NEXT: - FuncType: '(Int32, @inout XXX) -> Int32' // YAML-NEXT: ... struct XXX { init(t: T) mutating func foo(t: T) -> Int32 var m_t: T } // top_level_code sil private @top_level_code : $@convention(thin) () -> () { bb0: %0 = tuple () // user: %1 return %0 : $() // id: %1 } // specialize.XXX.init (specialize.XXX.Type)(t : A) -> specialize.XXX sil [noinline] @XXX_init : $@convention(thin) (@in T, @thin XXX.Type) -> @out XXX { bb0(%0 : $*XXX, %1 : $*T, %2 : $@thin XXX.Type): %3 = alloc_stack $XXX, var, name "sf" // users: %7, %11, %13 debug_value %1 : $*T, let, name "t", expr op_deref // id: %4 %5 = alloc_stack $T // users: %6, %8, %9 copy_addr %1 to [init] %5 : $*T // id: %6 %7 = struct_element_addr %3 : $*XXX, #XXX.m_t // user: %8 copy_addr [take] %5 to [init] %7 : $*T // id: %8 dealloc_stack %5 : $*T // id: %9 destroy_addr %1 : $*T // id: %10 copy_addr [take] %3 to [init] %0 : $*XXX // id: %11 %12 = tuple () // user: %14 dealloc_stack %3 : $*XXX // id: %13 return %12 : $() // id: %14 } // specialize.XXX.foo (@inout specialize.XXX)(t : A) -> Swift.Int32 sil [noinline] @XXX_foo : $@convention(method) (@in T, @inout XXX) -> Int32 { bb0(%0 : $*T, %1 : $*XXX): debug_value %0 : $*T, let, name "t", expr op_deref // id: %2 %3 = alloc_stack $T // users: %4, %6, %7 copy_addr %0 to [init] %3 : $*T // id: %4 %5 = struct_element_addr %1 : $*XXX, #XXX.m_t // user: %6 copy_addr [take] %3 to %5 : $*T // id: %6 dealloc_stack %3 : $*T // id: %7 %8 = integer_literal $Builtin.Int32, 4 // user: %9 %9 = struct $Int32 (%8 : $Builtin.Int32) // user: %11 destroy_addr %0 : $*T // id: %10 return %9 : $Int32 // id: %11 } // Swift.Int32._convertFromBuiltinIntegerLiteral (Swift.Int32.Type)(Builtin.IntLiteral) -> Swift.Int32 sil public_external [transparent] @$sSi33_convertFromBuiltinIntegerLiteralySiBI_cSimF : $@convention(thin) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 { bb0(%0 : $Builtin.IntLiteral, %1 : $@thin Int32.Type): %3 = builtin "s_to_s_checked_trunc_IntLiteral_Int32"(%0 : $Builtin.IntLiteral) : $(Builtin.Int32, Builtin.Int1) %4 = tuple_extract %3 : $(Builtin.Int32, Builtin.Int1), 0 // user: %5 %5 = struct $Int32 (%4 : $Builtin.Int32) // user: %6 return %5 : $Int32 // id: %6 } // specialize.acceptsInt (Swift.Int32) -> () sil [noinline] @acceptsInt : $@convention(thin) (Int32) -> () { bb0(%0 : $Int32): debug_value %0 : $Int32, let, name "x" // id: %1 %2 = tuple () // user: %3 return %2 : $() // id: %3 } // specialize.exp1 () -> () sil @exp1 : $@convention(thin) () -> () { bb0: %0 = alloc_stack $XXX, var, name "II" // users: %7, %15, %19 // function_ref specialize.XXX.init (specialize.XXX.Type)(t : A) -> specialize.XXX %1 = function_ref @XXX_init : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin XXX<τ_0_0>.Type) -> @out XXX<τ_0_0> // user: %7 %2 = metatype $@thin XXX.Type // user: %7 %3 = alloc_stack $Int32 // users: %6, %7, %8 %4 = integer_literal $Builtin.Int32, 5 // user: %5 %5 = struct $Int32 (%4 : $Builtin.Int32) // user: %6 store %5 to %3 : $*Int32 // id: %6 %7 = apply %1(%0, %3, %2) : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin XXX<τ_0_0>.Type) -> @out XXX<τ_0_0> dealloc_stack %3 : $*Int32 // id: %8 // function_ref specialize.acceptsInt (Swift.Int32) -> () %9 = function_ref @acceptsInt : $@convention(thin) (Int32) -> () // user: %16 // function_ref specialize.XXX.foo (@inout specialize.XXX)(t : A) -> Swift.Int32 %10 = function_ref @XXX_foo : $@convention(method) <τ_0_0> (@in τ_0_0, @inout XXX<τ_0_0>) -> Int32 // user: %15 %11 = alloc_stack $Int32 // users: %14, %15, %17 %12 = integer_literal $Builtin.Int32, 4 // user: %13 %13 = struct $Int32 (%12 : $Builtin.Int32) // user: %14 store %13 to %11 : $*Int32 // id: %14 %15 = apply %10(%11, %0) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout XXX<τ_0_0>) -> Int32 // user: %16 %16 = apply %9(%15) : $@convention(thin) (Int32) -> () dealloc_stack %11 : $*Int32 // id: %17 %18 = tuple () // user: %20 dealloc_stack %0 : $*XXX // id: %19 return %18 : $() // id: %20 } // specialize.exp2 () -> () sil @exp2 : $@convention(thin) () -> () { bb0: %0 = alloc_stack $XXX, var, name "I8" // users: %7, %15, %19 // function_ref specialize.XXX.init (specialize.XXX.Type)(t : A) -> specialize.XXX %1 = function_ref @XXX_init : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin XXX<τ_0_0>.Type) -> @out XXX<τ_0_0> // user: %7 %2 = metatype $@thin XXX.Type // user: %7 %3 = alloc_stack $UInt8 // users: %6, %7, %8 %4 = integer_literal $Builtin.Int8, 5 // user: %5 %5 = struct $UInt8 (%4 : $Builtin.Int8) // user: %6 store %5 to %3 : $*UInt8 // id: %6 %7 = apply %1(%0, %3, %2) : $@convention(thin) <τ_0_0> (@in τ_0_0, @thin XXX<τ_0_0>.Type) -> @out XXX<τ_0_0> dealloc_stack %3 : $*UInt8 // id: %8 // function_ref specialize.acceptsInt (Swift.Int32) -> () %9 = function_ref @acceptsInt : $@convention(thin) (Int32) -> () // user: %16 // function_ref specialize.XXX.foo (@inout specialize.XXX)(t : A) -> Swift.Int32 %10 = function_ref @XXX_foo : $@convention(method) <τ_0_0> (@in τ_0_0, @inout XXX<τ_0_0>) -> Int32 // user: %15 %11 = alloc_stack $UInt8 // users: %14, %15, %17 %12 = integer_literal $Builtin.Int8, 4 // user: %13 %13 = struct $UInt8 (%12 : $Builtin.Int8) // user: %14 store %13 to %11 : $*UInt8 // id: %14 %15 = apply %10(%11, %0) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout XXX<τ_0_0>) -> Int32 // user: %16 %16 = apply %9(%15) : $@convention(thin) (Int32) -> () dealloc_stack %11 : $*UInt8 // id: %17 %18 = tuple () // user: %20 dealloc_stack %0 : $*XXX // id: %19 return %18 : $() // id: %20 } // specialize.useClosure (fun : () -> A) -> A sil @useClosure : $@convention(thin) (@owned @callee_owned () -> @out T) -> @out T { bb0(%0 : $*T, %1 : $@callee_owned () -> @out T): debug_value %1 : $@callee_owned () -> @out T, let, name "fun" // id: %2 strong_retain %1 : $@callee_owned () -> @out T // id: %3 %4 = apply %1(%0) : $@callee_owned () -> @out T strong_release %1 : $@callee_owned () -> @out T // id: %5 %6 = tuple () // user: %7 return %6 : $() // id: %7 } // specialize.getGenericClosure (t : A) -> () -> A sil @getGenericClosure : $@convention(thin) (@in T) -> @owned @callee_owned () -> @out T { bb0(%0 : $*T): debug_value %0 : $*T, let, name "t", expr op_deref // id: %1 // function_ref specialize.(getGenericClosure (t : A) -> () -> A).(tmp #1) (())A %2 = function_ref @getGenericClosure_closure : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0 // user: %5 %3 = alloc_box $<τ_0_0> { var τ_0_0 } // users: %4, %5, %5 %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } , 0 copy_addr %0 to [init] %3a : $*T // id: %4 %5 = partial_apply %2(%3) : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0 // user: %7 destroy_addr %0 : $*T // id: %6 return %5 : $@callee_owned () -> @out T // id: %7 } // specialize.(getGenericClosure (t : A) -> () -> A).(tmp #1) (()) sil shared @getGenericClosure_closure : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> @out T { bb0(%0 : $*T, %1 : $<τ_0_0> { var τ_0_0 } ): %2 = project_box %1 : $<τ_0_0> { var τ_0_0 } , 0 copy_addr %2 to [init] %0 : $*T // id: %3 strong_release %1 : $<τ_0_0> { var τ_0_0 } // id: %4 %5 = tuple () // user: %6 return %5 : $() // id: %6 } // specialize.specializePartialApplies () -> Swift.UInt8 sil @specializePartialApplies : $@convention(thin) () -> UInt8 { bb0: %0 = alloc_stack $UInt8, var, name "i" // users: %3, %18 %1 = integer_literal $Builtin.Int8, 5 // user: %2 %2 = struct $UInt8 (%1 : $Builtin.Int8) // users: %3, %7 store %2 to %0 : $*UInt8 // id: %3 // function_ref specialize.useClosure (fun : () -> A) -> A %4 = function_ref @useClosure : $@convention(thin) <τ_0_0> (@owned @callee_owned () -> @out τ_0_0) -> @out τ_0_0 // user: %14 // function_ref specialize.getGenericClosure (t : A) -> () -> A %5 = function_ref @getGenericClosure : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @owned @callee_owned () -> @out τ_0_0 // user: %8 %6 = alloc_stack $UInt8 // users: %7, %8, %17 store %2 to %6 : $*UInt8 // id: %7 %8 = apply %5(%6) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @owned @callee_owned () -> @out τ_0_0 // user: %10 // function_ref reabstraction thunk helper from @callee_owned () -> (@out Swift.UInt8) to @callee_owned () -> (@unowned Swift.UInt8) %9 = function_ref @$ss5UInt8VIxr_ABIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out UInt8) -> UInt8 // user: %10 %10 = partial_apply %9(%8) : $@convention(thin) (@owned @callee_owned () -> @out UInt8) -> UInt8 // user: %12 // function_ref reabstraction thunk helper from @callee_owned () -> (@unowned Swift.UInt8) to @callee_owned () -> (@out Swift.UInt8) %11 = function_ref @$ss5UInt8VIxd_ABIxr_TR : $@convention(thin) (@owned @callee_owned () -> UInt8) -> @out UInt8 // user: %12 %12 = partial_apply %11(%10) : $@convention(thin) (@owned @callee_owned () -> UInt8) -> @out UInt8 // user: %14 %13 = alloc_stack $UInt8 // users: %14, %15, %16 %14 = apply %4(%13, %12) : $@convention(thin) <τ_0_0> (@owned @callee_owned () -> @out τ_0_0) -> @out τ_0_0 %15 = load %13 : $*UInt8 // user: %19 dealloc_stack %13 : $*UInt8 // id: %16 dealloc_stack %6 : $*UInt8 // id: %17 dealloc_stack %0 : $*UInt8 // id: %18 return %15 : $UInt8 // id: %19 } // reabstraction thunk helper from @callee_owned () -> (@out Swift.UInt8) to @callee_owned () -> (@unowned Swift.UInt8) sil shared [transparent] @$ss5UInt8VIxr_ABIxd_TR : $@convention(thin) (@owned @callee_owned () -> @out UInt8) -> UInt8 { bb0(%0 : $@callee_owned () -> @out UInt8): %1 = alloc_stack $UInt8 // users: %2, %3, %4 %2 = apply %0(%1) : $@callee_owned () -> @out UInt8 %3 = load %1 : $*UInt8 // user: %5 dealloc_stack %1 : $*UInt8 // id: %4 return %3 : $UInt8 // id: %5 } // reabstraction thunk helper from @callee_owned () -> (@unowned Swift.UInt8) to @callee_owned () -> (@out Swift.UInt8) sil shared [transparent] @$ss5UInt8VIxd_ABIxr_TR : $@convention(thin) (@owned @callee_owned () -> UInt8) -> @out UInt8 { bb0(%0 : $*UInt8, %1 : $@callee_owned () -> UInt8): %2 = apply %1() : $@callee_owned () -> UInt8 // user: %3 store %2 to %0 : $*UInt8 // id: %3 %4 = tuple () // user: %5 return %4 : $() // id: %5 } class Base { } sil_vtable Base { } sil @generic_upcast : $@convention(thin) (@owned T) -> @owned Base { bb0(%0 : $T): %2 = upcast %0 : $T to $Base return %2 : $Base } sil @specialize_generic_upcast : $@convention(thin)(@owned Base) -> @owned Base { bb0(%0 : $Base): %1 = function_ref @generic_upcast : $@convention(thin) (@owned T) -> @owned Base %2 = apply %1(%0) : $@convention(thin) (@owned T) -> @owned Base return %2 : $Base } // CHECK-LABEL: sil shared @{{.*}}generic_upcast{{.*}}Tg5 : $@convention(thin) (@owned Base) -> @owned Base { // CHECK: bb0(%0 : $Base): // CHECK: return %0 : $Base // YAML: Line: 277 // YAML: Column: 8 // YAML-NEXT: Function: specialize_generic_upcast // YAML-NEXT: Args: // YAML-NEXT: - String: 'Specialized function ' // YAML-NEXT: - Function: '"generic_upcast"' // YAML-NEXT: DebugLoc: // YAML: File: {{.*}}/specialize.sil // YAML: Line: 268 // YAML: Column: 6 // YAML-NEXT: - String: ' with type ' // YAML-NEXT: - FuncType: '(@owned Base) -> @owned Base' // YAML-NEXT: ... // Check generic specialization of partial_apply protocol P { func get() -> Int32 } struct C : P { func get() -> Int32 } // test4.C.get (test4.C)() -> Swift.Int32 sil hidden @C_get : $@convention(method) (C) -> Int32 { bb0(%0 : $C): debug_value %0 : $C, let, name "self" // id: %1 %2 = integer_literal $Builtin.Int32, 1 // user: %3 %3 = struct $Int32 (%2 : $Builtin.Int32) // user: %4 return %3 : $Int32 // id: %4 } // test4.C.init (test4.C.Type)() -> test4.C sil hidden [noinline] @C_init : $@convention(thin) (@thin C.Type) -> C { bb0(%0 : $@thin C.Type): %1 = alloc_stack $C, var, name "sf" // user: %3 %2 = struct $C () // user: %4 dealloc_stack %1 : $*C // id: %3 return %2 : $C // id: %4 } // protocol witness for test4.P.get (test4.P.Self)() -> Swift.Int32 in conformance test4.C : test4.P in test4 sil hidden [transparent] [thunk] @test4_P_get_witness_C : $@convention(witness_method: P) (@in_guaranteed C) -> Int32 { bb0(%0 : $*C): %1 = load %0 : $*C // user: %3 // function_ref test4.C.get (test4.C)() -> Swift.Int32 %2 = function_ref @C_get : $@convention(method) (C) -> Int32 // user: %3 %3 = apply %2(%1) : $@convention(method) (C) -> Int32 // user: %4 return %3 : $Int32 // id: %4 } // test4.boo (A) -> (Swift.Int32, B) -> Swift.Int32 sil hidden [noinline] @boo : $@convention(thin) (@in U) -> @owned @callee_owned (Int32, @in T) -> Int32 { bb0(%0 : $*U): debug_value %0 : $*U, let, name "y", expr op_deref // id: %1 // function_ref test4.(boo (A) -> (Swift.Int32, B) -> Swift.Int32).(closure #1) %2 = function_ref @boo_closure : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P> (Int32, @in τ_0_1, @owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> Int32 // user: %5 %3 = alloc_box $<τ_0_0> { var τ_0_0 } // users: %4, %5, %5 %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } , 0 copy_addr %0 to [init] %3a : $*U // id: %4 %5 = partial_apply %2(%3) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P> (Int32, @in τ_0_1, @owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> Int32 // user: %7 destroy_addr %0 : $*U // id: %6 return %5 : $@callee_owned (Int32, @in T) -> Int32 // id: %7 } // test4.(boo (A) -> (Swift.Int32, B) -> Swift.Int32).(closure #1) sil shared [noinline] @boo_closure : $@convention(thin) (Int32, @in T, @owned <τ_0_0> { var τ_0_0 } ) -> Int32 { bb0(%0 : $Int32, %1 : $*T, %2 : $<τ_0_0> { var τ_0_0 } ): %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } , 0 debug_value %0 : $Int32, let, name "x" // id: %4 debug_value %1 : $*T, let, name "z", expr op_deref // id: %5 %6 = witness_method $U, #P.get : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int32 // user: %7 %7 = apply %6(%3) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int32 // user: %8 %8 = struct_extract %7 : $Int32, #Int32._value // user: %11 %9 = struct_extract %0 : $Int32, #Int32._value // user: %11 %10 = integer_literal $Builtin.Int1, -1 // user: %11 %11 = builtin "sadd_with_overflow_Int32"(%8 : $Builtin.Int32, %9 : $Builtin.Int32, %10 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %12, %13 %12 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 0 // user: %15 %13 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 1 // user: %14 cond_fail %13 : $Builtin.Int1 // id: %14 %15 = struct $Int32 (%12 : $Builtin.Int32) // user: %18 strong_release %2 : $<τ_0_0> { var τ_0_0 } // id: %16 destroy_addr %1 : $*T // id: %17 return %15 : $Int32 // id: %18 } // static Swift.+ infix (Swift.Int32, Swift.Int32) -> Swift.Int32 sil public_external [transparent] @$ss1poiys5Int32VAC_ACtFZ : $@convention(thin) (Int32, Int32) -> Int32 { bb0(%0 : $Int32, %1 : $Int32): %2 = struct_extract %0 : $Int32, #Int32._value // user: %5 %3 = struct_extract %1 : $Int32, #Int32._value // user: %5 %4 = integer_literal $Builtin.Int1, -1 // user: %5 %5 = builtin "sadd_with_overflow_Int32"(%2 : $Builtin.Int32, %3 : $Builtin.Int32, %4 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %6, %7 %6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0 // user: %9 %7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1 // user: %8 cond_fail %7 : $Builtin.Int1 // id: %8 %9 = struct $Int32 (%6 : $Builtin.Int32) // user: %10 return %9 : $Int32 // id: %10 } // test4.foo (A, B) -> (Swift.Int32, Swift.Float) -> Swift.Int32 sil hidden [noinline] @foo : $@convention(thin) (@in T, @in U) -> @owned @callee_owned (Int32, Float) -> Int32 { bb0(%0 : $*T, %1 : $*U): debug_value %0 : $*T, let, name "x", expr op_deref // id: %2 debug_value %1 : $*U, let, name "y", expr op_deref // id: %3 // function_ref test4.boo (A) -> (Swift.Int32, B) -> Swift.Int32 %4 = function_ref @boo : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P> (@in τ_0_0) -> @owned @callee_owned (Int32, @in τ_0_1) -> Int32 // user: %7 %5 = alloc_stack $U // users: %6, %7, %10 copy_addr %1 to [init] %5 : $*U // id: %6 %7 = apply %4(%5) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P> (@in τ_0_0) -> @owned @callee_owned (Int32, @in τ_0_1) -> Int32 // user: %9 // function_ref reabstraction thunk helper from @callee_owned (@unowned Swift.Int32, @in Swift.Float) -> (@unowned Swift.Int32) to @callee_owned (@unowned Swift.Int32, @unowned Swift.Float) -> (@unowned Swift.Int32) %8 = function_ref @_TTRG1_RPq_P5test41P_Pq0_PS0___XFo_dVs5Int32iSf_dS1__XFo_dS1_dSf_dS1__ : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : P> (Int32, Float, @owned @callee_owned (Int32, @in Float) -> Int32) -> Int32 // user: %9 %9 = partial_apply %8(%7) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : P> (Int32, Float, @owned @callee_owned (Int32, @in Float) -> Int32) -> Int32 // user: %13 dealloc_stack %5 : $*U // id: %10 destroy_addr %1 : $*U // id: %11 destroy_addr %0 : $*T // id: %12 return %9 : $@callee_owned (Int32, Float) -> Int32 // id: %13 } // reabstraction thunk helper from @callee_owned (@unowned Swift.Int32, @in Swift.Float) -> (@unowned Swift.Int32) to @callee_owned (@unowned Swift.Int32, @unowned Swift.Float) -> (@unowned Swift.Int32) sil shared [transparent] [thunk] @_TTRG1_RPq_P5test41P_Pq0_PS0___XFo_dVs5Int32iSf_dS1__XFo_dS1_dSf_dS1__ : $@convention(thin) (Int32, Float, @owned @callee_owned (Int32, @in Float) -> Int32) -> Int32 { bb0(%0 : $Int32, %1 : $Float, %2 : $@callee_owned (Int32, @in Float) -> Int32): %3 = alloc_stack $Float // users: %4, %5, %6 store %1 to %3 : $*Float // id: %4 %5 = apply %2(%0, %3) : $@callee_owned (Int32, @in Float) -> Int32 // user: %7 dealloc_stack %3 : $*Float // id: %6 return %5 : $Int32 // id: %7 } // test4.gen1 (A) -> (Swift.Int32) -> Swift.Int32 sil hidden [noinline] @gen1 : $@convention(thin) (@in T) -> @owned @callee_owned (Int32) -> Int32 { bb0(%0 : $*T): debug_value %0 : $*T, let, name "x", expr op_deref // id: %1 // function_ref test4.(gen1 (A) -> (Swift.Int32) -> Swift.Int32).(closure #1) %2 = function_ref @gen1_closure : $@convention(thin) <τ_0_0 where τ_0_0 : P> (Int32, @owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> Int32 // user: %5 %3 = alloc_box $<τ_0_0> { var τ_0_0 } // users: %4, %5, %5 %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } , 0 copy_addr %0 to [init] %3a : $*T // id: %4 %5 = partial_apply %2(%3) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (Int32, @owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> Int32 // user: %7 destroy_addr %0 : $*T // id: %6 return %5 : $@callee_owned (Int32) -> Int32 // id: %7 } // test4.(gen1 (A) -> (Swift.Int32) -> Swift.Int32).(closure #1) sil shared [noinline] @gen1_closure : $@convention(thin) (Int32, @owned <τ_0_0> { var τ_0_0 } ) -> Int32 { bb0(%0 : $Int32, %1 : $<τ_0_0> { var τ_0_0 } ): %2 = project_box %1 : $<τ_0_0> { var τ_0_0 } , 0 debug_value %0 : $Int32 , let, name "$0" // id: %3 %4 = witness_method $T, #P.get : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int32 // user: %5 %5 = apply %4(%2) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int32 // user: %6 %6 = struct_extract %5 : $Int32, #Int32._value // user: %9 %7 = struct_extract %0 : $Int32, #Int32._value // user: %9 %8 = integer_literal $Builtin.Int1, -1 // user: %9 %9 = builtin "sadd_with_overflow_Int32"(%6 : $Builtin.Int32, %7 : $Builtin.Int32, %8 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %10, %11 %10 = tuple_extract %9 : $(Builtin.Int32, Builtin.Int1), 0 // user: %13 %11 = tuple_extract %9 : $(Builtin.Int32, Builtin.Int1), 1 // user: %12 cond_fail %11 : $Builtin.Int1 // id: %12 %13 = struct $Int32 (%10 : $Builtin.Int32) // user: %15 strong_release %1 : $<τ_0_0> { var τ_0_0 } // id: %14 return %13 : $Int32 // id: %15 } // check that there is a generic specialization of boo // CHECK-LABEL: sil shared [noinline] @$s3booxs5Int32VSfACIexyid_4main1PRzSfRs_r0_lIetio_Tp5AD1CV_Tg5 : $@convention(thin) (C) -> @owned @callee_owned (Int32, @in Float) -> Int32 // CHECK: [[CLOSURE_SPECIALIZATION:%[0-9]+]] = function_ref @$s11boo_closures5Int32VSfxz_x_lXXAC4main1PRzSfRs_r0_lIetyyxd_TP5AD1CV_TG5 // CHECK: partial_apply [[CLOSURE_SPECIALIZATION:%[0-9]+]] // CHECK: return // Check that there is a generic specialization of a closure from boo // CHECK-LABEL: sil shared [noinline] @$s11boo_closures5Int32VSfxz_x_lXXAC4main1PRzSfRs_r0_lIetyyxd_Tp5AD1CV_Tg5 // CHECK: return // Check that there is a generic specialization of foo // CHECK-LABEL: sil shared [noinline] @$s3foo4main1CV_ADTg5 : $@convention(thin) (C, C) -> @owned @callee_owned (Int32, Float) -> Int32 // CHECK: function_ref @$s3booxs5Int32VSfACIexyid_4main1PRzSfRs_r0_lIetio_Tp5AD1CV_Tg5 // check that it invokes a generic specialization of the reabstraction thunk helper which invokes a specialization boo // CHECK: [[THUNK_SPECIALIZATION:%[0-9]+]] = function_ref @$s053_TTRG1_RPq_P5test41P_Pq0_PS0___XFo_dVs5Int32iSf_dS1__f2_dj2_di2_dJ2__4main1CV_ADTg5 // CHECK-NOT: apply // CHECK: partial_apply [[THUNK_SPECIALIZATION]] // CHECK-NOT: apply // CHECK: return // Check that there is a generic specialization of gen1 // CHECK-LABEL: sil shared [noinline] @$s4gen14main1CV_Tg5 : $@convention(thin) (C) -> @owned @callee_owned (Int32) -> Int32 // check that it invokes a generic specialization of the closure by mean of partial_apply // CHECK: [[CLOSURE_SPECIALIZATION:%[0-9]+]] = function_ref @$s12gen1_closure4main1CV_Tg5 // CHECK-NOT: apply // CHECK: partial_apply [[CLOSURE_SPECIALIZATION]] // CHECK-NOT: apply // CHECK: return // Check that there is a generic specialization of a closure from gen1 // CHECK-LABEL: sil shared [noinline] @$s12gen1_closure4main1CV_Tg5 : $@convention(thin) (Int32, @owned <τ_0_0> { var τ_0_0 } ) -> Int32 // CHECK: return // test4.bar () -> Swift.Int32 // CHECK-LABEL: sil hidden @bar // check that it does not invoke a generic specialization of foo // CHECK-NOT: function_ref @foo // check that it invokes a generic specialization of foo // CHECK: function_ref @$s3foo4main1CV_ADTg5 sil hidden @bar : $@convention(thin) () -> Int32 { bb0: %0 = alloc_stack $@callee_owned (Int32, Float) -> Int32, var, name "f" // users: %11, %22 // function_ref test4.C.init (test4.C.Type)() -> test4.C %1 = function_ref @C_init : $@convention(thin) (@thin C.Type) -> C // user: %3 %2 = metatype $@thin C.Type // user: %3 %3 = apply %1(%2) : $@convention(thin) (@thin C.Type) -> C // users: %4, %7, %9 debug_value %3 : $C, let, name "c" // id: %4 // function_ref test4.foo (A, B) -> (Swift.Int32, Swift.Float) -> Swift.Int32 %5 = function_ref @foo : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : P> (@in τ_0_0, @in τ_0_1) -> @owned @callee_owned (Int32, Float) -> Int32 // user: %10 %6 = alloc_stack $C // users: %7, %10, %13 store %3 to %6 : $*C // id: %7 %8 = alloc_stack $C // users: %9, %10, %12 store %3 to %8 : $*C // id: %9 %10 = apply %5(%6, %8) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P, τ_0_1 : P> (@in τ_0_0, @in τ_0_1) -> @owned @callee_owned (Int32, Float) -> Int32 // users: %11, %14, %20, %21 store %10 to %0 : $*@callee_owned (Int32, Float) -> Int32 // id: %11 dealloc_stack %8 : $*C // id: %12 dealloc_stack %6 : $*C // id: %13 strong_retain %10 : $@callee_owned (Int32, Float) -> Int32 // id: %14 %15 = integer_literal $Builtin.Int32, 3 // user: %16 %16 = struct $Int32 (%15 : $Builtin.Int32) // user: %20 %17 = float_literal $Builtin.FPIEEE80, 0x4000C8F5C28F5C28F5C3 // 3.1400000000000000001 // user: %18 %18 = builtin "fptrunc_FPIEEE80_FPIEEE32"(%17 : $Builtin.FPIEEE80) : $Builtin.FPIEEE32 // user: %19 %19 = struct $Float (%18 : $Builtin.FPIEEE32) // user: %20 %20 = apply %10(%16, %19) : $@callee_owned (Int32, Float) -> Int32 // user: %23 strong_release %10 : $@callee_owned (Int32, Float) -> Int32 // id: %21 dealloc_stack %0 : $*@callee_owned (Int32, Float) -> Int32 // id: %22 return %20 : $Int32 // id: %23 } // test4.testBar () -> Swift.Int32 sil @testBar : $@convention(thin) () -> Int32 { bb0: // function_ref test4.bar () -> Swift.Int32 %0 = function_ref @bar : $@convention(thin) () -> Int32 // user: %1 %1 = apply %0() : $@convention(thin) () -> Int32 // user: %2 return %1 : $Int32 // id: %2 } // CHECK-LABEL: sil @testGen1 // Call of C_init // CHECK: function_ref @C_init // CHECK: apply // Reference to the generic specialization of gen1 // CHECK-NOT: function_ref @gen1 // CHECK: function_ref @$s4gen14main1CV_Tg5 : $@convention(thin) (C) -> @owned @callee_owned (Int32) -> Int32 sil @testGen1 : $@convention(thin) () -> Int32 { bb0: %0 = alloc_stack $@callee_owned (Int32) -> Int32, var, name "f" // users: %9, %16 // function_ref test4.C.init (test4.C.Type)() -> test4.C %1 = function_ref @C_init : $@convention(thin) (@thin C.Type) -> C // user: %3 %2 = metatype $@thin C.Type // user: %3 %3 = apply %1(%2) : $@convention(thin) (@thin C.Type) -> C // users: %4, %7 debug_value %3 : $C, let, name "c" // id: %4 // function_ref test4.gen1 (A) -> (Swift.Int32) -> Swift.Int32 %5 = function_ref @gen1 : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> @owned @callee_owned (Int32) -> Int32 // user: %8 %6 = alloc_stack $C // users: %7, %8, %10 store %3 to %6 : $*C // id: %7 %8 = apply %5(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in τ_0_0) -> @owned @callee_owned (Int32) -> Int32 // users: %9, %11, %14, %15 store %8 to %0 : $*@callee_owned (Int32) -> Int32 // id: %9 dealloc_stack %6 : $*C // id: %10 strong_retain %8 : $@callee_owned (Int32) -> Int32 // id: %11 %12 = integer_literal $Builtin.Int32, 3 // user: %13 %13 = struct $Int32 (%12 : $Builtin.Int32) // user: %14 %14 = apply %8(%13) : $@callee_owned (Int32) -> Int32 // user: %17 strong_release %8 : $@callee_owned (Int32) -> Int32 // id: %15 dealloc_stack %0 : $*@callee_owned (Int32) -> Int32 // id: %16 return %14 : $Int32 // id: %17 } // test_bind (Builtin.RawPointer, A.Type) -> () // Check that this is specialized as T=Int. // CHECK-LABEL: sil shared @$s9test_bindSi_Tt0g5 : $@convention(thin) (Builtin.RawPointer) -> () // CHECK: bind_memory %0 : $Builtin.RawPointer, {{%.*}} : $Builtin.Word to $*Int // CHECK: return sil hidden @test_bind : $@convention(thin) (Builtin.RawPointer, @thick T.Type) -> () { bb0(%0 : $Builtin.RawPointer, %1 : $@thick T.Type): %4 = integer_literal $Builtin.Word, 1 %5 = metatype $@thick T.Type %6 = bind_memory %0 : $Builtin.RawPointer, %4 : $Builtin.Word to $*T %7 = tuple () %8 = tuple () return %8 : $() } // Invoke test_bind with T=Int. sil @call_bind : $@convention(thin) (Builtin.RawPointer) -> () { bb0(%0 : $Builtin.RawPointer): // function_ref test_bind (Builtin.RawPointer, A.Type) -> () %2 = function_ref @test_bind : $@convention(thin) <τ_0_0> (Builtin.RawPointer, @thick τ_0_0.Type) -> () %3 = metatype $@thick Int.Type %4 = apply %2(%0, %3) : $@convention(thin) <τ_0_0> (Builtin.RawPointer, @thick τ_0_0.Type) -> () %5 = tuple () return %5 : $() } // invokeGenericClosure(todo:) sil [noinline] @invokeGenericClosure : $@convention(thin) (@owned @callee_owned () -> (@out R, @error Error)) -> (@out R, @error Error) { bb0(%0 : $*R, %1 : $@callee_owned () -> (@out R, @error Error)): debug_value %1 : $@callee_owned () -> (@out R, @error Error), let, name "todo", argno 1 // id: %2 debug_value undef : $Error, var, name "$error", argno 2 // id: %3 strong_retain %1 : $@callee_owned () -> (@out R, @error Error) // id: %4 try_apply %1(%0) : $@callee_owned () -> (@out R, @error Error), normal bb1, error bb2 // id: %5 bb1(%6 : $()): // Preds: bb0 strong_release %1 : $@callee_owned () -> (@out R, @error Error) // id: %7 %8 = tuple () // user: %9 return %8 : $() // id: %9 // %10 // user: %12 bb2(%10 : $Error): // Preds: bb0 strong_release %1 : $@callee_owned () -> (@out R, @error Error) // id: %11 throw %10 : $Error // id: %12 } // end sil function 'invokeGenericClosure' sil public_external @error : $@convention(thin) () -> Never // action() sil @action : $@convention(thin) () -> Never // thunk for @callee_owned () -> (@unowned Never, @error @owned Error) sil @action_thunk : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error) // Check that in a case where a generic specialization is a non-return function, // the return value is not stored after the call and an unreachable instruction // is inserted as a terminator of a basic block. // // CHECK-LABEL: sil @testGenericClosureSpecialization // Call of the generic specialization of invokeGenericClosure // CHECK: function_ref @$s20invokeGenericClosures5NeverO_Tg5 : $@convention(thin) (@owned @callee_owned () -> (@out Never, @error any Error)) -> (Never, @error any Error) // CHECK: apply [nothrow] // CHECK: unreachable // CHECK: end sil function 'testGenericClosureSpecialization' sil @testGenericClosureSpecialization : $@convention(thin) () -> @error Error { bb0: // function_ref invokeGenericClosure(todo:) %1 = function_ref @invokeGenericClosure : $@convention(thin) <τ_0_0> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error) %2 = alloc_stack $Never // function_ref action() %3 = function_ref @action : $@convention(thin) () -> Never %4 = thin_to_thick_function %3 : $@convention(thin) () -> Never to $@callee_owned () -> Never %5 = convert_function %4 : $@callee_owned () -> Never to $@callee_owned () -> (Never, @error Error) // function_ref thunk for @callee_owned () -> (@unowned Never, @error @owned Error) %6 = function_ref @action_thunk : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error) %7 = partial_apply %6(%5) : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error) %8 = apply [nothrow] %1(%2, %7) : $@convention(thin) <τ_0_0> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error) unreachable } // end sil function 'testGenericClosureSpecialization' // Test a specialization of a self-recursive generic closure. // CHECK-LABEL: sil shared @$s27selfReferringGenericClosurexBi64_Bi64_Bi64_Rs_r0_lIetnyy_Tp5 : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 == Builtin.Int64> (@in_guaranteed τ_0_0, Builtin.Int64, Builtin.Int64) -> () { // CHECK: [[SPECIALIZED_FN:%[0-9]+]] = function_ref @$s27selfReferringGenericClosurexBi64_Bi64_Bi64_Rs_r0_lIetnyy_Tp5 // CHECK: partial_apply [[SPECIALIZED_FN]]{{.*}}({{.*}}) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 == Builtin.Int64> (@in_guaranteed τ_0_0, Builtin.Int64, Builtin.Int64) -> () // CHECK-LABEL: sil @selfReferringGenericClosure : $@convention(thin) (@in_guaranteed R, @in_guaranteed S, Builtin.Int64) -> () // Refer to the specialized version of the function // CHECK: [[SPECIALIZED_FN:%[0-9]+]] = function_ref @$s27selfReferringGenericClosurexBi64_Bi64_Bi64_Rs_r0_lIetnyy_Tp5 // CHECK: partial_apply [[SPECIALIZED_FN]]({{.*}}) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 == Builtin.Int64> (@in_guaranteed τ_0_0, Builtin.Int64, Builtin.Int64) -> () sil @selfReferringGenericClosure : $@convention(thin) (@in_guaranteed R, @in_guaranteed S, Builtin.Int64) -> () { bb0(%0 : $*R, %1 : $*S, %2 : $Builtin.Int64): %4 = integer_literal $Builtin.Int64, 100 %5 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1 cond_br %5, bb2, bb1 bb1: %val_storage = alloc_stack $Builtin.Int64 %val = integer_literal $Builtin.Int64, 4 store %val to %val_storage : $*Builtin.Int64 %fn = function_ref @selfReferringGenericClosure : $@convention(thin) (@in_guaranteed U, @in_guaranteed V, Builtin.Int64) -> () %7 = partial_apply %fn(%0, %val_storage, %4) : $@convention(thin) (@in_guaranteed U, @in_guaranteed V, Builtin.Int64) -> () dealloc_stack %val_storage : $*Builtin.Int64 br bb3 bb2: br bb3 bb3: %8 = tuple () return %8 : $() } struct YYY { } enum MyOptional { case none case some(T) } // Check that a specialization of a self-recursive function is produced // and it is not crashing the compiler. // CHECK-LABEL: sil shared @$s25testSelfRecursiveFunction4main10MyOptionalOyAB3YYYVyypGG_Tg5 : $@convention(thin) (MyOptional>) -> () sil @testSelfRecursiveFunction : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): %2 = function_ref @testSelfRecursiveFunction : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () %3 = alloc_stack $MyOptional> inject_enum_addr %3 : $*MyOptional>, #MyOptional.none!enumelt %5 = tuple () %6 = load %3 : $*MyOptional> %7 = alloc_stack $MyOptional> store %6 to %7 : $*MyOptional> %9 = apply %2>>(%7) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () dealloc_stack %7 : $*MyOptional> dealloc_stack %3 : $*MyOptional> destroy_addr %0 : $*T %13 = tuple () return %13 : $() } // end sil function 'testSelfRecursiveFunction' sil @id : $@convention(thin) (@in T) -> @out T { bb0(%0 : $*T, %1 :$*T): copy_addr [take] %1 to [init] %0 : $*T %t = tuple () return %t : $() } // This should not assert. // CHECK-LABEL: sil shared @$s26specialize_no_return_applys5NeverO_Ttg5 // CHECK: apply // CHECK-NEXT: unreachable sil @specialize_no_return_apply: $@convention(thin) (@thick T.Type) -> () { bb0(%0 : $@thick T.Type): %in = alloc_stack $T %out = alloc_stack $T %f = function_ref @id : $@convention(thin) (@in T) -> @out T %r = apply %f(%out, %in) : $@convention(thin) (@in T) -> @out T dealloc_stack %out : $*T dealloc_stack %in : $*T %t = tuple () return %t : $() } sil @test_specialize_noreturn_apply : $@convention(thin) () -> () { bb0: %f = function_ref @specialize_no_return_apply : $@convention(thin) (@thick T.Type) -> () %m = metatype $@thick Never.Type %r = apply %f(%m) : $@convention(thin) (@thick T.Type) -> () %t = tuple () return %t : $() } sil shared @closure : $@convention(thin) (@in_guaranteed T) -> () { bb0(%0 : $*T): %5 = tuple () return %5 : $() } sil @getExistingExternalSpecialization : $@convention(thin) (@in_guaranteed T) -> @owned @callee_owned () -> () { bb0(%0 : $*T): %2 = function_ref @closure : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () %5 = partial_apply %2(%0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () return %5 : $@callee_owned () -> () } // Make sure we don't crash here // CHECK-LABEL: sil @testExistingExternalSpecialization : // CHECK: function_ref @$s33getExistingExternalSpecializations5UInt8V_Tg5 // CHECK: } // end sil function 'testExistingExternalSpecialization' sil @testExistingExternalSpecialization : $@convention(thin) () -> () { bb0: %0 = alloc_stack $UInt8 %1 = integer_literal $Builtin.Int8, 5 %2 = struct $UInt8 (%1 : $Builtin.Int8) store %2 to %0 : $*UInt8 %5 = function_ref @getExistingExternalSpecialization : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned @callee_owned () -> () %8 = apply %5(%0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned @callee_owned () -> () dealloc_stack %0 : $*UInt8 %r = tuple () return %r : $() } sil @$s7closures5UInt8V_Tg5 : $@convention(thin) (UInt8) -> ()