Files
swift-mirror/test/SILOptimizer/funcsig_explode_heuristic_inline.sil
Nate Chandler 9567bd4341 [SILOptimizer] Alter FSO arg explosion heuristic.
The new rule is that an argument will be exploded if one of the
following sets of conditions hold:

(1) (a) Specializing the function will result in a thunk.  That is, the
        thunk that is generated cannot be inlined everywhere.
    (b) The argument has dead non-trivial leaves.
    (c) The argument has fewer than three live leaves.

(2) (a) Specializing the function will not result in a thunk.  That is,
        the thunk that is generated will be inlined everywhere and
        eliminated as dead code.
    (b) The argument has dead potentially trivial leaves.
    (c) The argument has fewer than six live leaves.

This change is based heavily on @gottesm's
https://github.com/apple/swift/pull/16756 .

rdar://problem/39957093
2019-09-24 15:59:28 -07:00

91 lines
4.8 KiB
Plaintext

// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all -sil-inline-generics -inline -function-signature-opts -enable-expand-all %s | %FileCheck %s
sil_stage canonical
import Builtin
//////////////////
// Declarations //
//////////////////
class Klass {}
struct LargeNonTrivialStructOneNonTrivialField {
var k1: Klass
var k2: Klass
var x1: Builtin.Int32
var x2: Builtin.Int32
var x3: Builtin.Int32
var x4: Builtin.Int32
}
sil @consuming_user : $@convention(thin) (@owned Klass) -> ()
sil @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
// This test makes sure that if we have two non-trivial values that are live and
// one is always dead and the other is a value that we have a release for, we
// can get rid of the first argument and FSO the other. Test here that we
// explode it appropriately and do a partial o2g even though we aren't reducing
// the number of non-trivial uses.
// CHECK-LABEL: sil @caller1 : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
// CHECK: bb0([[ARG:%.*]] : $LargeNonTrivialStructOneNonTrivialField):
// CHECK: [[FUNC:%.*]] = function_ref @partial_o2g : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> ()
// CHECK: apply [[FUNC]]([[ARG]]) : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> ()
// CHECK: } // end sil function 'caller1'
sil @caller1 : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
%1 = function_ref @partial_o2g : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> ()
apply %1(%0) : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> ()
%9999 = tuple()
return %9999 : $()
}
// If we have two non-trivial values that are live and one is always dead and
// the other is kept alive due to a release, we can get rid of both since FSO
// reruns with o2g. Test here that we explode it appropriately and do a partial
// o2g even though we aren't reducing the number of non-trivial uses.
sil hidden [noinline] @partial_o2g : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
%2 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k2
%3 = function_ref @consuming_user : $@convention(thin) (@owned Klass) -> ()
apply %3(%2) : $@convention(thin) (@owned Klass) -> ()
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
apply %4(%1) :$@convention(thin) (@guaranteed Klass) -> ()
release_value %1 : $Klass
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @caller2 : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
// CHECK: bb0([[ARG:%.*]] : $LargeNonTrivialStructOneNonTrivialField):
// CHECK: [[FIELD1:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k2
// CHECK: [[FIELD2:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
// CHECK: [[FUNC:%.*]] = function_ref @$s23partiallydead_after_o2gTf4x_nTf4dn_n : $@convention(thin) (@owned Klass) -> ()
// CHECK: apply [[FUNC]]([[FIELD1]]) : $@convention(thin) (@owned Klass) -> ()
// CHECK: release_value [[FIELD2]]
// CHECK: } // end sil function 'caller2'
sil @caller2 : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
%1 = function_ref @partiallydead_after_o2g : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> ()
apply %1(%0) : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> ()
%9999 = tuple()
return %9999 : $()
}
// If we have two non-trivial values that are live and one is always dead and
// the other is kept alive due to a release, we can get rid of both since FSO
// reruns with o2g. Test here that we explode it appropriately and do a partial
// o2g even though we aren't reducing the number of non-trivial uses.
sil hidden [noinline] @partiallydead_after_o2g : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
%2 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k2
%3 = function_ref @consuming_user : $@convention(thin) (@owned Klass) -> ()
apply %3(%2) : $@convention(thin) (@owned Klass) -> ()
release_value %1 : $Klass
%9999 = tuple()
return %9999 : $()
}