Files
swift-mirror/test/AutoDiff/SILOptimizer/closure_specialization/single_bb.sil
Erik Eckstein df20d36255 ClosureSpecialization: support for OSSA and a big overhaul
Beside supporting OSSA, this change significantly simplifies the pass.
The main change is that instead of starting at a closure (e.g. `partial_apply`) and finding all call sites, we now start at a call site and look for closures for all arguments. This makes a lot of things much simpler, e.g. not so many intermediate data structures are required to track all the states.

I needed to remove the 3 unit tests because the things those tests were testing are not there anymore. However, the pass is tested with a lot of sil tests (and I added quite a few), which should give good test coverage.

The old ClosureSpecializer pass is still kept in place, because at that point in the pipeline we don't have OSSA, yet. Once we have that, we can replace the old pass withe the new one.
However, the autodiff closure specializer already runs in the OSSA pipeline and there the new changes take effect.
2025-10-06 12:02:48 +02:00

377 lines
28 KiB
Plaintext

// RUN: %target-sil-opt -sil-print-types -autodiff-closure-specialization -sil-combine %s -o - | %FileCheck %s --check-prefixes=COMBINE,CHECK
// REQUIRES: swift_in_compiler
sil_stage canonical
import Builtin
import Swift
import SwiftShims
import _Differentiation
////////////////////////////////////////////////////////////////
// Single closure call site where closure is passed as @owned //
////////////////////////////////////////////////////////////////
sil @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
sil private [ossa] @$pullback_f : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float {
bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> (Float, Float)):
%2 = apply %1(%0) : $@callee_guaranteed (Float) -> (Float, Float)
destroy_value %1
%4 = tuple_extract %2 : $(Float, Float), 0
%5 = tuple_extract %2 : $(Float, Float), 1
%6 = struct_extract %5 : $Float, #Float._value
%7 = struct_extract %4 : $Float, #Float._value
%8 = builtin "fadd_FPIEEE32"(%6 : $Builtin.FPIEEE32, %7 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%9 = struct $Float (%8 : $Builtin.FPIEEE32)
return %9 : $Float
}
// reverse-mode derivative of f(_:)
sil hidden [ossa] @$s4test1fyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
bb0(%0 : $Float):
// CHECK: sil private [ossa] @$s11$pullback_f12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float {
// CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float):
// CHECK: %[[#A2:]] = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// COMBINE: %[[#]] = apply %[[#A2]](%0, %1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// CHECK: sil hidden [ossa] @$s4test1fyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
// CHECK: bb0(%0 : $Float):
// CHECK: %[[#A4:]] = struct_extract %0 : $Float, #Float._value
// CHECK: %[[#A5:]] = builtin "fmul_FPIEEE32"(%[[#A4]] : $Builtin.FPIEEE32, %[[#A4]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
// CHECK: %[[#A6:]] = struct $Float (%[[#A5]] : $Builtin.FPIEEE32)
// COMBINE-NOT: function_ref @$vjpMultiply
// CHECK: %[[#A7:]] = function_ref @$s11$pullback_f12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float
// CHECK: %[[#A8:]] = partial_apply [callee_guaranteed] %[[#A7]](%0, %0) : $@convention(thin) (Float, Float, Float) -> Float
// CHECK: %[[#A9:]] = tuple (%[[#A6]] : $Float, %[[#A8]] : $@callee_guaranteed (Float) -> Float)
// CHECK: return %[[#A9]]
%2 = struct_extract %0 : $Float, #Float._value
%3 = builtin "fmul_FPIEEE32"(%2 : $Builtin.FPIEEE32, %2 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%4 = struct $Float (%3 : $Builtin.FPIEEE32)
// function_ref closure #1 in static Float._vjpMultiply(lhs:rhs:)
%5 = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
%6 = partial_apply [callee_guaranteed] %5(%0, %0) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// function_ref pullback of f(_:)
%7 = function_ref @$pullback_f : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float
%8 = partial_apply [callee_guaranteed] %7(%6) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float
%9 = tuple (%4 : $Float, %8 : $@callee_guaranteed (Float) -> Float)
return %9 : $(Float, @callee_guaranteed (Float) -> Float)
}
/////////////////////////////////////////////////////////////////////
// Single closure call site where closure is passed as @guaranteed //
/////////////////////////////////////////////////////////////////////
sil private [ossa] @$pullback_k : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float {
bb0(%0 : $Float, %1 : @guaranteed $@callee_guaranteed (Float) -> (Float, Float)):
%2 = apply %1(%0) : $@callee_guaranteed (Float) -> (Float, Float)
%3 = tuple_extract %2 : $(Float, Float), 0
%4 = tuple_extract %2 : $(Float, Float), 1
%5 = struct_extract %4 : $Float, #Float._value
%6 = struct_extract %3 : $Float, #Float._value
%7 = builtin "fadd_FPIEEE32"(%5 : $Builtin.FPIEEE32, %6 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%8 = struct $Float (%7 : $Builtin.FPIEEE32)
return %8 : $Float
} // end sil function '$pullback_k'
// reverse-mode derivative of k(_:)
sil hidden [ossa] @$s4test1kyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
bb0(%0 : $Float):
// CHECK: sil private [ossa] @$s11$pullback_k12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float {
// CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float):
// CHECK: %[[#B2:]] = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// COMBINE: %[[#]] = apply %[[#B2]](%0, %1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// CHECK: sil hidden [ossa] @$s4test1kyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
// CHECK: bb0(%0 : $Float):
// CHECK: %[[#B4:]] = struct_extract %0 : $Float, #Float._value
// CHECK: %[[#B5:]] = builtin "fmul_FPIEEE32"(%[[#B4]] : $Builtin.FPIEEE32, %[[#B4]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
// CHECK: %[[#B6:]] = struct $Float (%[[#B5]] : $Builtin.FPIEEE32)
// COMBINE-NOT: function_ref @$vjpMultiply
// CHECK: %[[#B7:]] = function_ref @$s11$pullback_k12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float
// CHECK: %[[#B8:]] = partial_apply [callee_guaranteed] %[[#B7]](%0, %0) : $@convention(thin) (Float, Float, Float) -> Float
// CHECK: %[[#B9:]] = tuple (%[[#B6]] : $Float, %[[#B8]] : $@callee_guaranteed (Float) -> Float)
// CHECK: return %[[#B9]]
%2 = struct_extract %0 : $Float, #Float._value
%3 = builtin "fmul_FPIEEE32"(%2 : $Builtin.FPIEEE32, %2 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%4 = struct $Float (%3 : $Builtin.FPIEEE32)
// function_ref $vjpMultiply
%5 = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
%6 = partial_apply [callee_guaranteed] %5(%0, %0) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// function_ref $pullback_k
%7 = function_ref @$pullback_k : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float
%8 = partial_apply [callee_guaranteed] %7(%6) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float
%10 = tuple (%4 : $Float, %8 : $@callee_guaranteed (Float) -> Float)
return %10 : $(Float, @callee_guaranteed (Float) -> Float)
} // end sil function '$s4test1kyS2fFTJrSpSr'
///////////////////////////////
// Multiple closure callsite //
///////////////////////////////
sil @$vjpSin : $@convention(thin) (Float, Float) -> Float
sil @$vjpCos : $@convention(thin) (Float, Float) -> Float
// pullback of g(_:)
sil private [ossa] @$pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float {
bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Float, %2 : @owned $@callee_guaranteed (Float) -> Float, %3 : @owned $@callee_guaranteed (Float) -> (Float, Float)):
%4 = apply %3(%0) : $@callee_guaranteed (Float) -> (Float, Float)
destroy_value %3 : $@callee_guaranteed (Float) -> (Float, Float)
%6 = tuple_extract %4 : $(Float, Float), 0
%7 = tuple_extract %4 : $(Float, Float), 1
%8 = apply %2(%7) : $@callee_guaranteed (Float) -> Float
destroy_value %2 : $@callee_guaranteed (Float) -> Float
%10 = apply %1(%6) : $@callee_guaranteed (Float) -> Float
destroy_value %1 : $@callee_guaranteed (Float) -> Float
%12 = struct_extract %8 : $Float, #Float._value
%13 = struct_extract %10 : $Float, #Float._value
%14 = builtin "fadd_FPIEEE32"(%13 : $Builtin.FPIEEE32, %12 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%15 = struct $Float (%14 : $Builtin.FPIEEE32)
return %15 : $Float
}
// reverse-mode derivative of g(_:)
sil hidden [ossa] @$s4test1gyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
bb0(%0 : $Float):
// CHECK: sil private [ossa] @$s11$pullback_g7$vjpSinSf0B3CosSf0B8MultiplyS2fTf1nccc_n : $@convention(thin) (Float, Float, Float, Float, Float) -> Float {
// CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float, %3 : $Float, %4 : $Float):
// CHECK: %[[#C4:]] = function_ref @$vjpSin : $@convention(thin) (Float, Float) -> Float
// CHECK: %[[#C6:]] = function_ref @$vjpCos : $@convention(thin) (Float, Float) -> Float
// CHECK: %[[#C8:]] = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// COMBINE: %[[#]] = apply %[[#C8]](%0, %3, %4) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// COMBINE: %[[#]] = apply %[[#C6]](%[[#]], %2) : $@convention(thin) (Float, Float) -> Float
// COMBINE: %[[#]] = apply %[[#C4]](%[[#]], %1) : $@convention(thin) (Float, Float) -> Float
// CHECK: sil hidden [ossa] @$s4test1gyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
// CHECK: bb0(%0 : $Float):
// CHECK: %[[#C10:]] = struct_extract %0 : $Float, #Float._value
// CHECK: %[[#C11:]] = builtin "int_sin_FPIEEE32"(%[[#C10]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
// CHECK: %[[#C12:]] = struct $Float (%[[#C11]] : $Builtin.FPIEEE32)
// COMBINE-NOT: function_ref @$vjpSin
// CHECK: %[[#C13:]] = builtin "int_cos_FPIEEE32"(%[[#C10]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
// COMBINE-NOT: function_ref @$vjpCos
// COMBINE-NOT: function_ref @$vjpMultiply
// CHECK: %[[#C14:]] = struct $Float (%[[#C13]] : $Builtin.FPIEEE32)
// CHECK: %[[#C15:]] = function_ref @$s11$pullback_g7$vjpSinSf0B3CosSf0B8MultiplyS2fTf1nccc_n : $@convention(thin) (Float, Float, Float, Float, Float) -> Float
// CHECK: %[[#C16:]] = partial_apply [callee_guaranteed] %[[#C15]](%0, %0, %[[#C14]], %[[#C12]]) : $@convention(thin) (Float, Float, Float, Float, Float) -> Float
// CHECK: %[[#C17:]] = tuple (%[[#]] : $Float, %[[#C16]] : $@callee_guaranteed (Float) -> Float)
// CHECK: return %[[#C17]]
%2 = struct_extract %0 : $Float, #Float._value
%3 = builtin "int_sin_FPIEEE32"(%2 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%4 = struct $Float (%3 : $Builtin.FPIEEE32)
// function_ref closure #1 in _vjpSin(_:)
%5 = function_ref @$vjpSin : $@convention(thin) (Float, Float) -> Float
%6 = partial_apply [callee_guaranteed] %5(%0) : $@convention(thin) (Float, Float) -> Float
%7 = builtin "int_cos_FPIEEE32"(%2 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%8 = struct $Float (%7 : $Builtin.FPIEEE32)
// function_ref closure #1 in _vjpCos(_:)
%9 = function_ref @$vjpCos : $@convention(thin) (Float, Float) -> Float
%10 = partial_apply [callee_guaranteed] %9(%0) : $@convention(thin) (Float, Float) -> Float
%11 = builtin "fmul_FPIEEE32"(%3 : $Builtin.FPIEEE32, %7 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
%12 = struct $Float (%11 : $Builtin.FPIEEE32)
// function_ref closure #1 in static Float._vjpMultiply(lhs:rhs:)
%13 = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float)
%14 = partial_apply [callee_guaranteed] %13(%8, %4) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// function_ref pullback of g(_:)
%15 = function_ref @$pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float
%16 = partial_apply [callee_guaranteed] %15(%6, %10, %14) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float
%17 = tuple (%12 : $Float, %16 : $@callee_guaranteed (Float) -> Float)
return %17 : $(Float, @callee_guaranteed (Float) -> Float)
}
///////////////////////////////
/// Parameter subset thunks ///
///////////////////////////////
struct X : Differentiable {
@_hasStorage var a: Float { get set }
@_hasStorage var b: Double { get set }
struct TangentVector : AdditiveArithmetic, Differentiable {
@_hasStorage var a: Float { get set }
@_hasStorage var b: Double { get set }
static func + (lhs: X.TangentVector, rhs: X.TangentVector) -> X.TangentVector
static func - (lhs: X.TangentVector, rhs: X.TangentVector) -> X.TangentVector
@_implements(Equatable, ==(_:_:)) static func __derived_struct_equals(_ a: X.TangentVector, _ b: X.TangentVector) -> Bool
typealias TangentVector = X.TangentVector
init(a: Float, b: Double)
static var zero: X.TangentVector { get }
}
init(a: Float, b: Double)
mutating func move(by offset: X.TangentVector)
}
sil [transparent] [thunk] @subset_parameter_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector
sil @pullback_f : $@convention(thin) (Float, Double) -> X.TangentVector
sil shared [ossa] @pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) -> X.TangentVector {
bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> X.TangentVector):
%2 = apply %1(%0) : $@callee_guaranteed (Float) -> X.TangentVector
destroy_value %1 : $@callee_guaranteed (Float) -> X.TangentVector
return %2 : $X.TangentVector
}
sil hidden [ossa] @$s5test21g1xSfAA1XV_tFTJrSpSr : $@convention(thin) (X) -> (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) {
bb0(%0 : $X):
// CHECK: sil shared [ossa] @$s10pullback_g0A2_fTf1nc_n : $@convention(thin) (Float) -> X.TangentVector {
// CHECK: bb0(%0 : $Float):
// CHECK: %[[#D3:]] = function_ref @subset_parameter_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector
// CHECK: %[[#D1:]] = function_ref @pullback_f : $@convention(thin) (Float, Double) -> X.TangentVector
// CHECK: %[[#D2:]] = thin_to_thick_function %[[#D1]] : $@convention(thin) (Float, Double) -> X.TangentVector to $@callee_guaranteed (Float, Double) -> X.TangentVector
// COMBINE: %[[#D5:]] = apply %[[#D3]](%0, %[[#D2]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector
// CHECK: return %[[#D5]]
// CHECK: sil hidden [ossa] @$s5test21g1xSfAA1XV_tFTJrSpSr : $@convention(thin) (X) -> (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) {
// CHECK: bb0(%0 : $X):
// CHECK: %[[#D6:]] = struct_extract %0 : $X, #X.a
// COMBINE-NOT: function_ref @pullback_f
// COMBINE-NOT: function_ref @subset_parameter_thunk
// CHECK: %[[#D7:]] = function_ref @$s10pullback_g0A2_fTf1nc_n : $@convention(thin) (Float) -> X.TangentVector
// COMBINE: %[[#D8:]] = thin_to_thick_function %[[#D7]] : $@convention(thin) (Float) -> X.TangentVector to $@callee_guaranteed (Float) -> X.TangentVector
// CHECK: %[[#D9:]] = tuple (%[[#D6]] : $Float, %[[#D8]] : $@callee_guaranteed (Float) -> X.TangentVector)
// CHECK: return %[[#D9]]
%1 = struct_extract %0 : $X, #X.a
// function_ref pullback_f
%2 = function_ref @pullback_f : $@convention(thin) (Float, Double) -> X.TangentVector
%3 = thin_to_thick_function %2 : $@convention(thin) (Float, Double) -> X.TangentVector to $@callee_guaranteed (Float, Double) -> X.TangentVector
// function_ref subset_parameter_thunk
%4 = function_ref @subset_parameter_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector
%5 = partial_apply [callee_guaranteed] %4(%3) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector
// function_ref pullback_g
%6 = function_ref @pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) -> X.TangentVector
%7 = partial_apply [callee_guaranteed] %6(%5) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) -> X.TangentVector
%8 = tuple (%1 : $Float, %7 : $@callee_guaranteed (Float) -> X.TangentVector)
return %8 : $(Float, @callee_guaranteed (Float) -> X.TangentVector)
}
///////////////////////////////////////////////////////////////////////
///////// Specialized generic closures - PartialApply Closure /////////
///////////////////////////////////////////////////////////////////////
// closure #1 in static Float._vjpMultiply(lhs:rhs:)
sil @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// thunk for @escaping @callee_guaranteed (@unowned Float) -> (@unowned Float, @unowned Float)
sil [transparent] [reabstraction_thunk] @$sS3fIegydd_S3fIegnrr_TR : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float)
// function_ref specialized pullback of f<A>(a:)
sil [transparent] [thunk] @pullback_f_specialized : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>) -> @out Float
// thunk for @escaping @callee_guaranteed (@in_guaranteed Float) -> (@out Float)
sil [transparent] [reabstraction_thunk] @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @pullback_h : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float {
bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Float):
%2 = apply %1(%0) : $@callee_guaranteed (Float) -> Float
destroy_value %1 : $@callee_guaranteed (Float) -> Float
return %2 : $Float
}
// reverse-mode derivative of h(x:)
sil hidden [ossa] @$s5test21h1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
bb0(%0 : $Float):
// CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s10pullback_h073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbackti1_j5FZSf_J6SfcfU_S2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float {
// CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float):
// CHECK: %[[#E8:]] = function_ref @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
// CHECK: %[[#E6:]] = function_ref @pullback_f_specialized : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>) -> @out Float
// CHECK: %[[#E3:]] = function_ref @$sS3fIegydd_S3fIegnrr_TR : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float)
// CHECK: %[[#E1:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// CHECK: %[[#E2:]] = partial_apply [callee_guaranteed] %[[#E1]](%1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// CHECK: %[[#E4:]] = partial_apply [callee_guaranteed] %[[#E3]](%[[#E2]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float)
// CHECK: %[[#E5:]] = convert_function %[[#E4]] : $@callee_guaranteed (@in_guaranteed Float) -> (@out Float, @out Float) to $@callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>
// CHECK: %[[#E7:]] = partial_apply [callee_guaranteed] %[[#E6]](%[[#E5]]) : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>) -> @out Float
// COMBINE: %[[#E10:]] = apply %[[#E8]](%0, %[[#E7]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
// COMBINE: destroy_value %[[#E7]] : $@callee_guaranteed (@in_guaranteed Float) -> @out Float
// CHECK: return %[[#E10]]
// CHECK: sil hidden [ossa] @$s5test21h1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
// CHECK: bb0(%0 : $Float):
// CHECK: %[[#E11:]] = struct_extract %0 : $Float, #Float._value
// CHECK: %[[#E12:]] = builtin "fmul_FPIEEE32"(%[[#E11]] : $Builtin.FPIEEE32, %1 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
// COMBINE-NOT: function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_
// COMBINE-NOT: function_ref @$sS3fIegydd_S3fIegnrr_TR
// COMBINE-NOT: function_ref @pullback_f_specialized
// COMBINE-NOT: function_ref @$sS2fIegnr_S2fIegyd_TR
// CHECK: %[[#E13:]] = struct $Float (%[[#E12]] : $Builtin.FPIEEE32)
// CHECK: %[[#E14:]] = function_ref @$s10pullback_h073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbackti1_j5FZSf_J6SfcfU_S2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float
// CHECK: %[[#E15:]] = partial_apply [callee_guaranteed] %[[#E14]](%0, %0) : $@convention(thin) (Float, Float, Float) -> Float
// CHECK: %[[#E16:]] = tuple (%[[#E13]] : $Float, %[[#E15]] : $@callee_guaranteed (Float) -> Float)
// CHECK: return %[[#E16]]
%1 = struct_extract %0 : $Float, #Float._value
%2 = builtin "fmul_FPIEEE32"(%1 : $Builtin.FPIEEE32, %1 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
// function_ref closure #1 in static Float._vjpMultiply(lhs:rhs:)
%3 = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float)
%4 = partial_apply [callee_guaranteed] %3(%0, %0) : $@convention(thin) (Float, Float, Float) -> (Float, Float)
// function_ref thunk for @escaping @callee_guaranteed (@unowned Float) -> (@unowned Float, @unowned Float)
%5 = function_ref @$sS3fIegydd_S3fIegnrr_TR : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float)
%6 = partial_apply [callee_guaranteed] %5(%4) : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float)
%7 = convert_function %6 : $@callee_guaranteed (@in_guaranteed Float) -> (@out Float, @out Float) to $@callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>
// function_ref pullback_f_specialized
%8 = function_ref @pullback_f_specialized : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>) -> @out Float
%9 = partial_apply [callee_guaranteed] %8(%7) : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for <Float, Float, Float>) -> @out Float
// function_ref thunk for @escaping @callee_guaranteed (@in_guaranteed Float) -> (@out Float)
%10 = function_ref @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
%11 = partial_apply [callee_guaranteed] %10(%9) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
%12 = struct $Float (%2 : $Builtin.FPIEEE32)
// function_ref pullback_h
%13 = function_ref @pullback_h : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float
%14 = partial_apply [callee_guaranteed] %13(%11) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float
%15 = tuple (%12 : $Float, %14 : $@callee_guaranteed (Float) -> Float)
return %15 : $(Float, @callee_guaranteed (Float) -> Float)
}
//////////////////////////////////////////////////////////////////////////////
///////// Specialized generic closures - ThinToThickFunction closure /////////
//////////////////////////////////////////////////////////////////////////////
sil [transparent] [thunk] @pullback_y_specialized : $@convention(thin) (@in_guaranteed Float) -> @out Float
sil [transparent] [reabstraction_thunk] @reabstraction_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @pullback_z : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float {
bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Float):
%2 = apply %1(%0) : $@callee_guaranteed (Float) -> Float
destroy_value %1 : $@callee_guaranteed (Float) -> Float
return %2 : $Float
}
sil hidden [ossa] @$s5test21z1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
bb0(%0 : $Float):
// CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s10pullback_z0A14_y_specializedTf1nc_n : $@convention(thin) (Float) -> Float {
// CHECK: bb0(%0 : $Float):
// CHECK: %[[#F3:]] = function_ref @reabstraction_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
// CHECK: %[[#F1:]] = function_ref @pullback_y_specialized : $@convention(thin) (@in_guaranteed Float) -> @out Float
// CHECK: %[[#F2:]] = thin_to_thick_function %[[#F1]] : $@convention(thin) (@in_guaranteed Float) -> @out Float to $@callee_guaranteed (@in_guaranteed Float) -> @out Float
// COMBINE: %[[#F5:]] = apply %[[#F3]](%0, %[[#F2]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
// CHECK: return %[[#F5]]
// CHECK: sil hidden [ossa] @$s5test21z1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) {
// CHECK: bb0(%0 : $Float):
// COMBINE-NOT: function_ref @pullback_y_specialized
// COMBINE-NOT: function_ref @reabstraction_thunk
// CHECK: %[[#F6:]] = function_ref @$s10pullback_z0A14_y_specializedTf1nc_n : $@convention(thin) (Float) -> Float
// COMBINE: %[[#F7:]] = thin_to_thick_function %[[#F6]] : $@convention(thin) (Float) -> Float to $@callee_guaranteed (Float) -> Float
// CHECK: %[[#F8:]] = tuple (%0 : $Float, %[[#F7]] : $@callee_guaranteed (Float) -> Float)
// CHECK: return %[[#F8]]
// function_ref pullback_y_specialized
%1 = function_ref @pullback_y_specialized : $@convention(thin) (@in_guaranteed Float) -> @out Float
%2 = thin_to_thick_function %1 : $@convention(thin) (@in_guaranteed Float) -> @out Float to $@callee_guaranteed (@in_guaranteed Float) -> @out Float
// function_ref reabstraction_thunk
%3 = function_ref @reabstraction_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
%4 = partial_apply [callee_guaranteed] %3(%2) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float
// function_ref pullback_z
%5 = function_ref @pullback_z : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float
%6 = partial_apply [callee_guaranteed] %5(%4) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float
%7 = tuple (%0 : $Float, %6 : $@callee_guaranteed (Float) -> Float)
return %7 : $(Float, @callee_guaranteed (Float) -> Float)
}