| // RUN: rm -rf %t && mkdir -p %t |
| // RUN: %target-sil-opt -enable-sil-verify-all %s -inline -debug-only=sil-inliner 2>%t/log | %FileCheck %s |
| // RUN: %FileCheck %s --check-prefix=CHECK-LOG <%t/log |
| // REQUIRES: asserts |
| |
| // 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) |
| } |
| |
| |
| // CHECK-LABEL: sil @testDirectClosure |
| // CHECK: [[C:%[0-9]+]] = thin_to_thick_function |
| // CHECK: apply [[C]]( |
| // CHECK: return |
| |
| // CHECK-LOG-LABEL: Inline into caller: testDirectClosure |
| // CHECK-LOG-NEXT: decision {{.*}}, b=70, |
| |
| sil @testDirectClosure : $@convention(thin) () -> Int32 { |
| bb0: |
| %0 = function_ref @takeDirectClosure : $@convention(thin) (@owned @callee_owned (Int32) -> Int32) -> Int32 |
| %1 = function_ref @closure : $@convention(thin) (Int32) -> Int32 |
| %2 = thin_to_thick_function %1 : $@convention(thin) (Int32) -> Int32 to $@callee_owned (Int32) -> Int32 |
| %3 = apply %0(%2) : $@convention(thin) (@owned @callee_owned (Int32) -> Int32) -> Int32 |
| return %3 : $Int32 |
| } |
| |
| sil @takeDirectClosure : $@convention(thin) (@owned @callee_owned (Int32) -> Int32) -> Int32 { |
| bb0(%0 : $@callee_owned (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_owned (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_owned (Int32) -> Int32 |
| %3 = struct $Cont (%2 : $@callee_owned (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_owned (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_owned (Int32) -> Int32 |
| %3 = struct $Cont (%2 : $@callee_owned (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_owned (Int32) -> Int32 |
| strong_release %8 : $@callee_owned (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_owned (Int32) -> Int32 |
| %3 = integer_literal $Builtin.Int32, 27 |
| %4 = struct $Int32 (%3 : $Builtin.Int32) |
| strong_retain %2 : $@callee_owned (Int32) -> Int32 |
| %6 = apply %2(%4) : $@callee_owned (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_owned (Int32) -> Int32 |
| %5 = tuple (%2 : $Int32, %4 : $@callee_owned (Int32) -> Int32) |
| %6 = struct $Cont2 (%5 : $(Int32, @callee_owned (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_owned (Int32) -> Int32), 1 |
| %3 = integer_literal $Builtin.Int32, 27 |
| %4 = struct $Int32 (%3 : $Builtin.Int32) |
| %5 = apply %2(%4) : $@callee_owned (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_owned (Int32) -> Int32 |
| %3 = enum $E, #E.B!enumelt.1, %2 : $@callee_owned (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.1 |
| %2 = integer_literal $Builtin.Int32, 27 |
| %3 = struct $Int32 (%2 : $Builtin.Int32) |
| %4 = apply %1(%3) : $@callee_owned (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) () -> () { |
| bb0: |
| |
| %0 = function_ref @condBrCallee : $@convention(thin) (Int32) -> Int32 |
| %1 = integer_literal $Builtin.Int32, 27 |
| %2 = struct $Int32 (%1 : $Builtin.Int32) |
| %3 = apply %0(%2) : $@convention(thin) (Int32) -> Int32 |
| %4 = tuple () |
| return %4 : $() |
| } |
| |
| sil @condBrCallee : $@convention(thin) (Int32) -> Int32 { |
| bb0(%0 : $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(%0 : $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=50, |
| |
| sil @testSwitchValue : $@convention(thin) () -> () { |
| bb0: |
| |
| %0 = function_ref @switchValueCallee : $@convention(thin) (Int32) -> Int32 |
| %1 = integer_literal $Builtin.Int32, 28 |
| %2 = struct $Int32 (%1 : $Builtin.Int32) |
| %3 = apply %0(%2) : $@convention(thin) (Int32) -> Int32 |
| %4 = tuple () |
| return %4 : $() |
| } |
| |
| sil @switchValueCallee : $@convention(thin) (Int32) -> Int32 { |
| bb0(%0 : $Int32): |
| %1 = integer_literal $Builtin.Int32, 27 |
| %2 = integer_literal $Builtin.Int32, 28 |
| %3 = struct_extract %0 : $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 @testSwitchEnum |
| // CHECK-NOT: apply |
| // CHECK: builtin "assert_configuration"() |
| // CHECK-NOT: apply |
| // CHECK: return %{{.*}} : $() |
| |
| // CHECK-LOG-LABEL: Inline into caller: testSwitchEnum |
| // CHECK-LOG-NEXT: decision {{.*}}, b=50, |
| |
| sil @testSwitchEnum : $@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.1, %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.1: bb1, case #Optional.none!enumelt: bb2 |
| |
| bb1: |
| %2 = unchecked_enum_data %0 : $Optional<Int32>, #Optional.some!enumelt.1 |
| 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 |
| } |
| |