Files
swift-mirror/test/SILOptimizer/inline_heuristics.sil
Arnold Schwaighofer 2fd904808c ConstantTracker: Look through mark_dependence instructions
An interposed mark_dependence should not block the heuristic that adds a
benefit when inlining a function that takes a closure argument.
2025-08-25 13:57:23 -07:00

605 lines
28 KiB
Plaintext

// RUN: %empty-directory(%t)
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -compute-side-effects -inline -sil-inline-generics=true -sil-partial-specialization=false -debug-only=sil-inliner 2>%t/log | %FileCheck %s
// RUN: %FileCheck %s --check-prefix=CHECK-LOG <%t/log
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -inline -sil-inline-generics=true -sil-partial-specialization=true -generic-specializer -debug-only=sil-inliner 2>%t/log | %FileCheck %s --check-prefix=CHECK-PARTIAL-SPECIALIZATION
// REQUIRES: asserts
// REQUIRES: swift_in_compiler
// This test checks the inline heuristics based on the debug log output of
// the performance inliner.
// Checking the final sil is just a goodie.
sil_stage canonical
import Builtin
import Swift
import SwiftShims
struct Cont {
var cl: (Int32) -> Int32
}
struct Cont2 {
var tp: (Int32, (Int32) -> Int32)
}
enum E {
case A
case B((Int32) -> Int32)
}
class C {
init()
}
// CHECK-LABEL: sil @testDirectClosure
// CHECK: [[C:%[0-9]+]] = thin_to_thick_function
// CHECK: [[MD:%[0-9]+]] = mark_dependence [[C]]
// CHECK: apply [[MD]](
// CHECK: return
// CHECK-LOG-LABEL: Inline into caller: testDirectClosure
// CHECK-LOG-NEXT: decision {{.*}}, b=70,
sil @testDirectClosure : $@convention(thin) (@guaranteed C) -> Int32 {
bb0(%c : $C):
%0 = function_ref @takeDirectClosure : $@convention(thin) (@owned @callee_guaranteed (Int32) -> Int32) -> Int32
%1 = function_ref @closure : $@convention(thin) (Int32) -> Int32
%2 = thin_to_thick_function %1 : $@convention(thin) (Int32) -> Int32 to $@callee_guaranteed (Int32) -> Int32
%3 = mark_dependence %2 on %c
%4 = apply %0(%3) : $@convention(thin) (@owned @callee_guaranteed (Int32) -> Int32) -> Int32
return %4 : $Int32
}
sil @takeDirectClosure : $@convention(thin) (@owned @callee_guaranteed (Int32) -> Int32) -> Int32 {
bb0(%0 : $@callee_guaranteed (Int32) -> Int32):
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%1 = integer_literal $Builtin.Int32, 27
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = apply %0(%2) : $@callee_guaranteed (Int32) -> Int32
return %3 : $Int32
}
// CHECK-LABEL: sil @testStructClosure
// CHECK: [[C:%[0-9]+]] = struct_extract
// CHECK: apply [[C]](
// CHECK: return
// CHECK-LOG-LABEL: Inline into caller: testStructClosure
// CHECK-LOG-NEXT: decision {{.*}}, b=70,
sil @testStructClosure : $@convention(thin) () -> Int32 {
bb0:
%0 = function_ref @takeStructClosure : $@convention(thin) (@owned Cont) -> Int32
%1 = function_ref @closure : $@convention(thin) (Int32) -> Int32
%2 = thin_to_thick_function %1 : $@convention(thin) (Int32) -> Int32 to $@callee_guaranteed (Int32) -> Int32
%3 = struct $Cont (%2 : $@callee_guaranteed (Int32) -> Int32)
%4 = apply %0(%3) : $@convention(thin) (@owned Cont) -> Int32
return %4 : $Int32
}
sil @takeStructClosure : $@convention(thin) (@owned Cont) -> Int32 {
bb0(%0 : $Cont):
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%1 = struct_extract %0 : $Cont, #Cont.cl
%2 = integer_literal $Builtin.Int32, 27
%3 = struct $Int32 (%2 : $Builtin.Int32)
%4 = apply %1(%3) : $@callee_guaranteed (Int32) -> Int32
return %4 : $Int32
}
// CHECK-LABEL: sil @testStructAddrClosure
// CHECK: [[C:%[0-9]+]] = load
// CHECK: apply [[C]](
// CHECK: return
// CHECK-LOG-LABEL: Inline into caller: testStructAddrClosure
// CHECK-LOG-NEXT: decision {{.*}}, b=70,
sil @testStructAddrClosure : $@convention(thin) () -> Int32 {
bb0:
%0 = alloc_stack $Cont
%1 = function_ref @closure : $@convention(thin) (Int32) -> Int32
%2 = thin_to_thick_function %1 : $@convention(thin) (Int32) -> Int32 to $@callee_guaranteed (Int32) -> Int32
%3 = struct $Cont (%2 : $@callee_guaranteed (Int32) -> Int32)
store %3 to %0 : $*Cont
%5 = function_ref @takeStructAddrClosure : $@convention(thin) (@inout Cont) -> Int32
%6 = apply %5(%0) : $@convention(thin) (@inout Cont) -> Int32
%7 = struct_element_addr %0 : $*Cont, #Cont.cl
%8 = load %7 : $*@callee_guaranteed (Int32) -> Int32
strong_release %8 : $@callee_guaranteed (Int32) -> Int32
dealloc_stack %0 : $*Cont
return %6 : $Int32
}
sil @takeStructAddrClosure : $@convention(thin) (@inout Cont) -> Int32 {
bb0(%0 : $*Cont):
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%1 = struct_element_addr %0 : $*Cont, #Cont.cl
%2 = load %1 : $*@callee_guaranteed (Int32) -> Int32
%3 = integer_literal $Builtin.Int32, 27
%4 = struct $Int32 (%3 : $Builtin.Int32)
strong_retain %2 : $@callee_guaranteed (Int32) -> Int32
%6 = apply %2(%4) : $@callee_guaranteed (Int32) -> Int32
return %6 : $Int32
}
// CHECK-LABEL: sil @testTupleClosure
// CHECK: [[C:%[0-9]+]] = tuple_extract
// CHECK: apply [[C]](
// CHECK: return
// CHECK-LOG-LABEL: Inline into caller: testTupleClosure
// CHECK-LOG-NEXT: decision {{.*}}, b=70,
sil @testTupleClosure : $@convention(thin) () -> Int32 {
bb0:
%0 = function_ref @takeTupleClosure : $@convention(thin) (@owned Cont2) -> Int32
%1 = integer_literal $Builtin.Int32, 27
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = function_ref @closure : $@convention(thin) (Int32) -> Int32
%4 = thin_to_thick_function %3 : $@convention(thin) (Int32) -> Int32 to $@callee_guaranteed (Int32) -> Int32
%5 = tuple (%2 : $Int32, %4 : $@callee_guaranteed (Int32) -> Int32)
%6 = struct $Cont2 (%5 : $(Int32, @callee_guaranteed (Int32) -> Int32))
%7 = apply %0(%6) : $@convention(thin) (@owned Cont2) -> Int32
return %7 : $Int32
}
sil @takeTupleClosure : $@convention(thin) (@owned Cont2) -> Int32 {
bb0(%0 : $Cont2):
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%1 = struct_extract %0 : $Cont2, #Cont2.tp
%2 = tuple_extract %1 : $(Int32, @callee_guaranteed (Int32) -> Int32), 1
%3 = integer_literal $Builtin.Int32, 27
%4 = struct $Int32 (%3 : $Builtin.Int32)
%5 = apply %2(%4) : $@callee_guaranteed (Int32) -> Int32
return %5 : $Int32
}
// CHECK-LABEL: sil @testEnumClosure
// CHECK: [[C:%[0-9]+]] = unchecked_enum_data
// CHECK: apply [[C]](
// CHECK: return
// CHECK-LOG-LABEL: Inline into caller: testEnumClosure
// CHECK-LOG-NEXT: decision {{.*}}, b=70,
sil @testEnumClosure : $@convention(thin) () -> Int32 {
bb0:
%0 = function_ref @takeEnumClosure : $@convention(thin) (@owned E) -> Int32
%1 = function_ref @closure : $@convention(thin) (Int32) -> Int32
%2 = thin_to_thick_function %1 : $@convention(thin) (Int32) -> Int32 to $@callee_guaranteed (Int32) -> Int32
%3 = enum $E, #E.B!enumelt, %2 : $@callee_guaranteed (Int32) -> Int32
%4 = apply %0(%3) : $@convention(thin) (@owned E) -> Int32
return %4 : $Int32
}
sil @takeEnumClosure : $@convention(thin) (@owned E) -> Int32 {
bb0(%0 : $E):
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%1 = unchecked_enum_data %0 : $E, #E.B!enumelt
%2 = integer_literal $Builtin.Int32, 27
%3 = struct $Int32 (%2 : $Builtin.Int32)
%4 = apply %1(%3) : $@callee_guaranteed (Int32) -> Int32
return %4 : $Int32
}
// The closure which is used by all tests above.
sil shared @closure : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
%1 = integer_literal $Builtin.Int32, 1
%2 = struct_extract %0 : $Int32, #Int32._value
%3 = integer_literal $Builtin.Int1, -1
%4 = builtin "sadd_with_overflow_Int32"(%2 : $Builtin.Int32, %1 : $Builtin.Int32, %3 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%5 = tuple_extract %4 : $(Builtin.Int32, Builtin.Int1), 0
%6 = tuple_extract %4 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %6 : $Builtin.Int1
%8 = struct $Int32 (%5 : $Builtin.Int32)
return %8 : $Int32
}
// CHECK-LABEL: sil @testCondBr
// CHECK-NOT: apply
// CHECK: builtin "assert_configuration"()
// CHECK-NOT: apply
// CHECK: return %{{.*}} : $()
// CHECK-LOG-LABEL: Inline into caller: testCondBr
// CHECK-LOG-NEXT: decision {{.*}}, b=50,
sil @testCondBr : $@convention(thin) (Int32) -> () {
bb0(%a : $Int32):
%0 = function_ref @condBrCallee : $@convention(thin) (Int32, Int32) -> Int32
%1 = integer_literal $Builtin.Int32, 27
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = apply %0(%2, %a) : $@convention(thin) (Int32, Int32) -> Int32
%4 = tuple ()
return %4 : $()
}
sil @condBrCallee : $@convention(thin) (Int32, Int32) -> Int32 {
bb0(%0 : $Int32, %r : $Int32):
%1 = integer_literal $Builtin.Int32, 27
%2 = struct_extract %0 : $Int32, #Int32._value
%3 = builtin "cmp_eq_Word"(%2 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1
cond_br %3, bb1, bb2
bb1:
br bb3(%r : $Int32)
bb2:
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%6 = struct $Int32 (%1 : $Builtin.Int32)
br bb3(%6 : $Int32)
bb3(%8 : $Int32):
return %8 : $Int32
}
// CHECK-LABEL: sil @testSwitchValue
// CHECK-NOT: apply
// CHECK: builtin "assert_configuration"()
// CHECK-NOT: apply
// CHECK: return %{{.*}} : $()
// CHECK-LOG-LABEL: Inline into caller: testSwitchValue
// CHECK-LOG-NEXT: decision {{.*}}, b=40,
sil @testSwitchValue : $@convention(thin) (Int32) -> () {
bb0(%a : $Int32):
%0 = function_ref @switchValueCallee : $@convention(thin) (Int32, Int32) -> Int32
%1 = integer_literal $Builtin.Int32, 28
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = apply %0(%2, %a) : $@convention(thin) (Int32, Int32) -> Int32
%4 = tuple ()
return %4 : $()
}
sil @switchValueCallee : $@convention(thin) (Int32, Int32) -> Int32 {
bb0(%0 : $Int32, %r : $Int32):
%1 = integer_literal $Builtin.Int32, 27
%2 = integer_literal $Builtin.Int32, 28
%3 = struct_extract %r : $Int32, #Int32._value
switch_value %3 : $Builtin.Int32, case %1 : bb1, case %2 : bb2, default bb3
bb1:
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
br bb4(%1 : $Builtin.Int32)
bb2:
br bb4(%2 : $Builtin.Int32)
bb3:
// increase the scope length
%c3 = builtin "assert_configuration"() : $Builtin.Int32
%c4 = builtin "assert_configuration"() : $Builtin.Int32
br bb4(%1 : $Builtin.Int32)
bb4(%8 : $Builtin.Int32):
%9 = struct $Int32 (%8 : $Builtin.Int32)
return %9 : $Int32
}
// CHECK-LABEL: sil @testSwitchEnumArg
// CHECK-NOT: apply
// CHECK: builtin "assert_configuration"()
// CHECK-NOT: apply
// CHECK: return %{{.*}} : $()
// CHECK-LOG-LABEL: Inline into caller: testSwitchEnumArg
// CHECK-LOG-NEXT: decision {{.*}}, b=50,
sil @testSwitchEnumArg : $@convention(thin) (Builtin.Int32) -> () {
bb0(%1 : $Builtin.Int32):
%0 = function_ref @switchEnumCallee : $@convention(thin) (Optional<Int32>) -> Int32
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = enum $Optional<Int32>, #Optional.some!enumelt, %2 : $Int32
%4 = apply %0(%3) : $@convention(thin) (Optional<Int32>) -> Int32
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: sil @testSwitchEnumConst
// CHECK-NOT: apply
// CHECK: builtin "assert_configuration"()
// CHECK-NOT: apply
// CHECK: return %{{.*}} : $()
// CHECK-LOG-LABEL: Inline into caller: testSwitchEnumConst
// CHECK-LOG-NEXT: pure-call decision
sil @testSwitchEnumConst : $@convention(thin) () -> () {
bb0:
%0 = function_ref @switchEnumCallee : $@convention(thin) (Optional<Int32>) -> Int32
%1 = integer_literal $Builtin.Int32, 27
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = enum $Optional<Int32>, #Optional.some!enumelt, %2 : $Int32
%4 = apply %0(%3) : $@convention(thin) (Optional<Int32>) -> Int32
%5 = tuple ()
return %5 : $()
}
sil @switchEnumCallee : $@convention(thin) (Optional<Int32>) -> Int32 {
bb0(%0 : $Optional<Int32>):
switch_enum %0 : $Optional<Int32>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
bb1:
%2 = unchecked_enum_data %0 : $Optional<Int32>, #Optional.some!enumelt
br bb3(%2 : $Int32)
bb2:
// increase the scope length
%c1 = builtin "assert_configuration"() : $Builtin.Int32
%c2 = builtin "assert_configuration"() : $Builtin.Int32
%4 = integer_literal $Builtin.Int32, 0
%5 = struct $Int32 (%4 : $Builtin.Int32)
br bb3(%5 : $Int32)
bb3(%7 : $Int32):
return %7 : $Int32
}
// Tests of the generics inlining.
// CHECK-LABEL: sil @testSpecializationAfterGenericInlining
// CHECK-NOT: apply
// CHECK: function_ref @action
// CHECK: apply
// CHECK-NOT: apply
// CHECK: return
// CHECK: end sil function 'testSpecializationAfterGenericInlining'
// CHECK-PARTIAL-SPECIALIZATION-LABEL: sil @testSpecializationAfterGenericInlining
// CHECK-PARTIAL-SPECIALIZATION-NOT: apply
// Reference to the partial specialization of checkSpecializationAfterGenericInlining
// CHECK-PARTIAL-SPECIALIZATION: function_ref @$s39checkSpecializationAfterGenericInlinings5Int64Vq_ACRszr0_lIetyi_Tp5
// CHECK-PARTIAL-SPECIALIZATION: apply
// CHECK-PARTIAL-SPECIALIZATION-NOT: apply
// CHECK-PARTIAL-SPECIALIZATION: return
// CHECK-PARTIAL-SPECIALIZATION: end sil function 'testSpecializationAfterGenericInlining'
// Check that the inlining heuristic takes into account the possibility
// of performing a generic specialization after inlining.
// CHECK-LOG-LABEL: Inline into caller: testSpecializationAfterGenericInlining
// CHECK-LOG-NEXT: decision {{.*}}, b=320, {{.*}} checkSpecializationAfterGenericInlining
sil hidden [noinline] @action : $@convention(thin) <T> (@in T) -> () {
bb0(%0 : $*T):
destroy_addr %0 : $*T
%3 = tuple ()
return %3 : $()
} // end sil function 'action'
// checkSpecializationAfterGenericInlining<A, B> (A, B) -> ()
sil hidden @checkSpecializationAfterGenericInlining : $@convention(thin) <T, U> (@in T, @in U) -> () {
bb0(%0 : $*T, %1 : $*U):
// function_ref action<A> (A) -> ()
%4 = function_ref @action : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
%5 = alloc_stack $T
copy_addr %0 to [init] %5 : $*T
%7 = apply %4<T>(%5) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
dealloc_stack %5 : $*T
destroy_addr %1 : $*U
destroy_addr %0 : $*T
%11 = tuple ()
return %11 : $()
} // end sil function 'checkSpecializationAfterGenericInlining'
sil @testSpecializationAfterGenericInlining : $@convention(thin) <U> (@in U) -> () {
bb0(%0 : $*U):
// function_ref checkSpecializationAfterGenericInlining<A, B> (A, B) -> ()
%2 = function_ref @checkSpecializationAfterGenericInlining : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> ()
%3 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%3 : $Builtin.Int64)
%5 = alloc_stack $Int64
store %4 to %5 : $*Int64
%7 = alloc_stack $U
copy_addr %0 to [init] %7 : $*U
%9 = apply %2<Int64, U>(%5, %7) : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> ()
dealloc_stack %7 : $*U
dealloc_stack %5 : $*Int64
destroy_addr %0 : $*U
%13 = tuple ()
return %13 : $()
} // end sil function 'testSpecializationAfterGenericInlining'
// Tests of exclusivity inlining.
// CHECK-LABEL: sil @testExclusivity : $@convention(thin) () -> () {
// CHECK-NOT: apply
// CHECK: begin_access
// CHECK: return
// CHECK: end sil function 'testExclusivity'
struct X {
@_hasStorage var i: Int64 { get set }
init(i: Int64)
init()
}
var globalX: X
sil_global hidden @globalX : $X
sil @exclusivityCallee : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalX: $*X
%1 = begin_access [read] [dynamic] [no_nested_conflict] %0 : $*X
%2 = load %1 : $*X
end_access %1 : $*X
%4 = tuple ()
return %4 : $()
}
sil @testExclusivity : $@convention(thin) () -> () {
bb0:
%0 = function_ref @exclusivityCallee : $@convention(thin) () -> ()
%1 = apply %0() : $@convention(thin) () -> ()
%2 = tuple ()
return %2 : $()
}
// TODO:
// Check that the inlining heuristic takes into account the possibility
// of performing a devirtualization after inlining.
// Test of inlining functions with many parameters
// CHECK-LABEL: sil @testManyParams : $@convention(thin) (Float,
// CHECK-NOT: apply
// CHECK: return
// CHECK: end sil function 'testManyParams'
sil @manyParamsCallee1 : $@convention(thin) (Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float) -> Float {
bb0(%0 : $Float, %1 : $Float, %2 : $Float, %3 : $Float, %4 : $Float, %5 : $Float, %6 : $Float, %7 : $Float, %8 : $Float, %9 : $Float, %10 : $Float, %11 : $Float, %12 : $Float, %13 : $Float, %14 : $Float, %15 : $Float, %16 : $Float, %17 : $Float, %18 : $Float):
%19 = struct_extract %10 : $Float, #Float._value // user: %21
%20 = struct_extract %0 : $Float, #Float._value // users: %65, %67, %60, %53, %55, %23, %21
%21 = builtin "fmul_FPIEEE32"(%19 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %27, %25
%22 = struct_extract %11 : $Float, #Float._value // user: %23
%23 = builtin "fmul_FPIEEE32"(%22 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %28
%24 = struct_extract %8 : $Float, #Float._value // user: %25
%25 = builtin "fmul_FPIEEE32"(%24 : $Builtin.FPIEEE32, %21 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %29
%26 = struct_extract %9 : $Float, #Float._value // user: %27
%27 = builtin "fmul_FPIEEE32"(%26 : $Builtin.FPIEEE32, %21 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %28
%28 = builtin "fadd_FPIEEE32"(%27 : $Builtin.FPIEEE32, %23 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %50
%29 = builtin "fneg_FPIEEE32"(%25 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %31
%30 = struct_extract %18 : $Float, #Float._value // user: %31
%31 = builtin "fdiv_FPIEEE32"(%29 : $Builtin.FPIEEE32, %30 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %34, %32
%33 = struct_extract %17 : $Float, #Float._value // user: %34
%34 = builtin "fdiv_FPIEEE32"(%31 : $Builtin.FPIEEE32, %33 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %36
%35 = struct_extract %16 : $Float, #Float._value // user: %36
%36 = builtin "fmul_FPIEEE32"(%35 : $Builtin.FPIEEE32, %34 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %43, %37
%38 = struct_extract %14 : $Float, #Float._value // users: %41, %41
%39 = struct_extract %15 : $Float, #Float._value // user: %40
%40 = builtin "fneg_FPIEEE32"(%39 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %42
%41 = builtin "fmul_FPIEEE32"(%38 : $Builtin.FPIEEE32, %38 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %42
%42 = builtin "fdiv_FPIEEE32"(%40 : $Builtin.FPIEEE32, %41 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %43
%43 = builtin "fmul_FPIEEE32"(%42 : $Builtin.FPIEEE32, %36 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %46, %44
%45 = struct_extract %13 : $Float, #Float._value // user: %46
%46 = builtin "fdiv_FPIEEE32"(%43 : $Builtin.FPIEEE32, %45 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %48
%47 = struct_extract %12 : $Float, #Float._value // user: %48
%48 = builtin "fmul_FPIEEE32"(%47 : $Builtin.FPIEEE32, %46 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %49, %50
%50 = builtin "fadd_FPIEEE32"(%48 : $Builtin.FPIEEE32, %28 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %51, %63
%52 = struct_extract %6 : $Float, #Float._value // user: %53
%53 = builtin "fmul_FPIEEE32"(%52 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %57
%54 = struct_extract %7 : $Float, #Float._value // user: %55
%55 = builtin "fmul_FPIEEE32"(%54 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %58
%56 = struct_extract %5 : $Float, #Float._value // user: %57
%57 = builtin "fmul_FPIEEE32"(%56 : $Builtin.FPIEEE32, %53 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %58
%58 = builtin "fadd_FPIEEE32"(%57 : $Builtin.FPIEEE32, %55 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %61
%59 = struct_extract %4 : $Float, #Float._value // user: %60
%60 = builtin "fmul_FPIEEE32"(%59 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %61
%61 = builtin "fadd_FPIEEE32"(%60 : $Builtin.FPIEEE32, %58 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %62, %63
%63 = builtin "fadd_FPIEEE32"(%61 : $Builtin.FPIEEE32, %50 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %75
%64 = struct_extract %2 : $Float, #Float._value // user: %65
%65 = builtin "fmul_FPIEEE32"(%64 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %69
%66 = struct_extract %3 : $Float, #Float._value // user: %67
%67 = builtin "fmul_FPIEEE32"(%66 : $Builtin.FPIEEE32, %20 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %70
%68 = struct_extract %1 : $Float, #Float._value // user: %69
%69 = builtin "fmul_FPIEEE32"(%68 : $Builtin.FPIEEE32, %65 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %70
%70 = builtin "fadd_FPIEEE32"(%69 : $Builtin.FPIEEE32, %67 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %73
%71 = integer_literal $Builtin.Int64, 0 // user: %72
%72 = builtin "sitofp_Int64_FPIEEE32"(%71 : $Builtin.Int64) : $Builtin.FPIEEE32 // user: %73
%73 = builtin "fadd_FPIEEE32"(%72 : $Builtin.FPIEEE32, %70 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %74, %75
%75 = builtin "fadd_FPIEEE32"(%73 : $Builtin.FPIEEE32, %63 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %76
%76 = struct $Float (%75 : $Builtin.FPIEEE32) // users: %78, %77
return %76 : $Float // id: %78
}
sil @manyParamsCallee2 : $@convention(thin) (Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float) -> Float {
bb0(%0 : $Float, %1 : $Float, %2 : $Float, %3 : $Float, %4 : $Float, %5 : $Float, %6 : $Float, %7 : $Float, %8 : $Float, %9 : $Float, %10 : $Float, %11 : $Float, %12 : $Float, %13 : $Float, %14 : $Float, %15 : $Float, %16 : $Float, %17 : $Float, %18 : $Float, %19 : $Float, %20 : $Float, %21 : $Float, %22 : $Float, %23 : $Float, %24 : $Float, %25 : $Float, %26 : $Float):
%27 = function_ref @manyParamsCallee1 : $@convention(thin) (Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float) -> Float
%28 = apply %27(%0, %2, %3, %4, %6, %8, %9, %10, %11, %12, %13, %14, %15, %17, %19, %20, %21, %23, %25) : $@convention(thin) (Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float) -> Float
return %28 : $Float
}
sil @testManyParams : $@convention(thin) (Float, Builtin.FPIEEE32, Builtin.FPIEEE32, Builtin.FPIEEE32) -> (Float, Float) {
bb0(%0 : $Float, %1 : @closureCapture $Builtin.FPIEEE32, %2 : @closureCapture $Builtin.FPIEEE32, %3 : @closureCapture $Builtin.FPIEEE32):
%4 = struct $Float (%3 : $Builtin.FPIEEE32)
%5 = struct $Float (%2 : $Builtin.FPIEEE32)
%11 = float_literal $Builtin.FPIEEE32, 0x47C35000 // 1.0E+5 // user: %12
%12 = builtin "fneg_FPIEEE32"(%11 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %15, %13
%13 = struct $Float (%12 : $Builtin.FPIEEE32) // user: %67
%14 = struct_extract %0 : $Float, #Float._value // users: %60, %58, %34, %23, %21, %19, %17, %15
%15 = builtin "fmul_FPIEEE32"(%12 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %17, %16
%16 = struct $Float (%15 : $Builtin.FPIEEE32) // user: %67
%17 = builtin "fmul_FPIEEE32"(%15 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %25
%19 = builtin "fmul_FPIEEE32"(%2 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %20
%20 = builtin "fadd_FPIEEE32"(%1 : $Builtin.FPIEEE32, %19 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %24
%21 = builtin "fmul_FPIEEE32"(%3 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %23, %22
%22 = struct $Float (%21 : $Builtin.FPIEEE32) // user: %67
%23 = builtin "fmul_FPIEEE32"(%21 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %24
%24 = builtin "fadd_FPIEEE32"(%20 : $Builtin.FPIEEE32, %23 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %25
%25 = builtin "fadd_FPIEEE32"(%17 : $Builtin.FPIEEE32, %24 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %61
%28 = float_literal $Builtin.FPIEEE32, 0x3C9C0EBF // 0.0190500002 // users: %50, %34, %29
%29 = struct $Float (%28 : $Builtin.FPIEEE32) // users: %67, %67, %30
%31 = float_literal $Builtin.FPIEEE32, 0x425AA3D7 // 54.6599998 // users: %48, %32
%32 = struct $Float (%31 : $Builtin.FPIEEE32) // users: %67, %33
%34 = builtin "fmul_FPIEEE32"(%14 : $Builtin.FPIEEE32, %28 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %38, %35
%35 = struct $Float (%34 : $Builtin.FPIEEE32) // user: %67
%36 = float_literal $Builtin.FPIEEE32, 0x34883033 // 2.53670436E-7 // users: %38, %37
%37 = struct $Float (%36 : $Builtin.FPIEEE32) // user: %67
%38 = builtin "fdiv_FPIEEE32"(%34 : $Builtin.FPIEEE32, %36 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %43, %39
%40 = float_literal $Builtin.FPIEEE32, 0x42800000 // 64 // users: %45, %41
%41 = struct $Float (%40 : $Builtin.FPIEEE32) // user: %67
%42 = float_literal $Builtin.FPIEEE32, 0x3C23D70A // 0.00999999977 // user: %43
%43 = builtin "fadd_FPIEEE32"(%38 : $Builtin.FPIEEE32, %42 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %45, %44
%44 = struct $Float (%43 : $Builtin.FPIEEE32) // user: %67
%45 = builtin "fdiv_FPIEEE32"(%40 : $Builtin.FPIEEE32, %43 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %48, %46
%46 = struct $Float (%45 : $Builtin.FPIEEE32) // users: %67, %47
%48 = builtin "fmul_FPIEEE32"(%45 : $Builtin.FPIEEE32, %31 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %50, %49
%49 = struct $Float (%48 : $Builtin.FPIEEE32) // user: %67
%50 = builtin "fdiv_FPIEEE32"(%48 : $Builtin.FPIEEE32, %28 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %55, %51
%51 = struct $Float (%50 : $Builtin.FPIEEE32) // users: %67, %52
%53 = float_literal $Builtin.FPIEEE32, 0x3929844A // 1.61663775E-4 // users: %55, %54
%54 = struct $Float (%53 : $Builtin.FPIEEE32) // user: %67
%55 = builtin "fdiv_FPIEEE32"(%50 : $Builtin.FPIEEE32, %53 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %56
%56 = builtin "fneg_FPIEEE32"(%55 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %58, %57
%57 = struct $Float (%56 : $Builtin.FPIEEE32) // user: %67
%58 = builtin "fmul_FPIEEE32"(%56 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // users: %60, %59
%59 = struct $Float (%58 : $Builtin.FPIEEE32) // user: %67
%60 = builtin "fmul_FPIEEE32"(%58 : $Builtin.FPIEEE32, %14 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %61
%61 = builtin "fadd_FPIEEE32"(%25 : $Builtin.FPIEEE32, %60 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 // user: %62
%62 = struct $Float (%61 : $Builtin.FPIEEE32) // user: %69
%63 = integer_literal $Builtin.Int64, 1 // user: %64
%64 = builtin "sitofp_Int64_FPIEEE32"(%63 : $Builtin.Int64) : $Builtin.FPIEEE32
%65 = struct $Float (%64 : $Builtin.FPIEEE32)
%66 = function_ref @manyParamsCallee2 : $@convention(thin) (Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float) -> Float
%67 = apply %66(%65, %0, %13, %0, %16, %0, %5, %0, %4, %0, %22, %0, %57, %0, %59, %29, %0, %37, %35, %44, %41, %32, %46, %29, %49, %54, %51) : $@convention(thin) (Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float, Float) -> Float // users: %69, %68
%69 = tuple (%62 : $Float, %67 : $Float) // user: %70
return %69 : $(Float, Float) // id: %70
}