mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
208 lines
12 KiB
Plaintext
208 lines
12 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-objc-interop -enable-sil-verify-all -function-signature-opts -sil-fso-disable-dead-argument -sil-fso-disable-owned-to-guaranteed -enable-expand-all -sil-fso-optimize-if-not-called %s | %FileCheck %s
|
|
|
|
// *NOTE* We turn off all other fso optimizations including dead arg so we can
|
|
// make sure that we are not exploding those.
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
|
|
//////////////////
|
|
// Declarations //
|
|
//////////////////
|
|
|
|
struct BigTrivial {
|
|
var x1: Builtin.Int32
|
|
var x2: Builtin.Int32
|
|
var x3: Builtin.Int32
|
|
var x4: Builtin.Int32
|
|
var x5: Builtin.Int32
|
|
var x6: Builtin.Int32
|
|
}
|
|
|
|
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 @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
sil @consuming_user : $@convention(thin) (@owned Klass) -> ()
|
|
sil @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
|
|
///////////
|
|
// Tests //
|
|
///////////
|
|
|
|
// We should never optimize this. If we did this would become a thunk, so we
|
|
// know that just be checking NFC we have proven no optimization has occurred.
|
|
//
|
|
// CHECK-LABEL: sil @never_explode_trivial : $@convention(thin) (BigTrivial) -> () {
|
|
// CHECK: } // end sil function 'never_explode_trivial'
|
|
sil @never_explode_trivial : $@convention(thin) (BigTrivial) -> () {
|
|
bb0(%0 : $BigTrivial):
|
|
%1 = struct_extract %0 : $BigTrivial, #BigTrivial.x1
|
|
%intfunc = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%1) : $@convention(thin) (Builtin.Int32) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// If a value is never used, do not touch it. We leave it for dead argument
|
|
// elimination. We have deliberately turned this off to test that behavior.
|
|
//
|
|
// CHECK-LABEL: sil @big_arg_with_no_uses : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
// CHECK-NOT: apply
|
|
// CHECK: } // end sil function 'big_arg_with_no_uses'
|
|
sil @big_arg_with_no_uses : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We are using a single non-trivial field of the struct. We should explode this
|
|
// so we eliminate the second non-trivial leaf.
|
|
//
|
|
// CHECK-LABEL: sil [signature_optimized_thunk] [always_inline] @big_arg_with_one_nontrivial_use : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : $LargeNonTrivialStructOneNonTrivialField):
|
|
// CHECK: [[FUNC:%.*]] = function_ref @$s31big_arg_with_one_nontrivial_useTf4x_n
|
|
// CHECK: [[FIELD:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
// CHECK: apply [[FUNC]]([[FIELD]])
|
|
// CHECK: } // end sil function 'big_arg_with_one_nontrivial_use'
|
|
sil @big_arg_with_one_nontrivial_use : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
%2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %2(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We are using a single non-trivial field and a single trivial field. We are
|
|
// willing to blow this up.
|
|
//
|
|
// CHECK-LABEL: sil [signature_optimized_thunk] [always_inline] @big_arg_with_one_nontrivial_use_one_trivial_use : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : $LargeNonTrivialStructOneNonTrivialField):
|
|
// CHECK: [[FUNC:%.*]] = function_ref @$s032big_arg_with_one_nontrivial_use_d9_trivial_F0Tf4x_n : $@convention(thin) (@guaranteed Klass, Builtin.Int32) -> ()
|
|
// CHECK: [[TRIVIAL_FIELD:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x1
|
|
// CHECK: [[NON_TRIVIAL_FIELD:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
// CHECK: apply [[FUNC]]([[NON_TRIVIAL_FIELD]], [[TRIVIAL_FIELD]])
|
|
// CHECK: } // end sil function 'big_arg_with_one_nontrivial_use_one_trivial_use'
|
|
sil @big_arg_with_one_nontrivial_use_one_trivial_use : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
%2 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x1
|
|
%3 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %3(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%intfunc = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%2) : $@convention(thin) (Builtin.Int32) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We can still explode this, since our limit is 3 values.
|
|
//
|
|
// CHECK-LABEL: sil [signature_optimized_thunk] [always_inline] @big_arg_with_one_nontrivial_use_two_trivial_uses : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : $LargeNonTrivialStructOneNonTrivialField):
|
|
// CHECK: [[FUNC:%.*]] = function_ref @$s48big_arg_with_one_nontrivial_use_two_trivial_usesTf4x_n : $@convention(thin)
|
|
// CHECK: [[TRIVIAL_FIELD1:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x2
|
|
// CHECK: [[TRIVIAL_FIELD2:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x1
|
|
// CHECK: [[NON_TRIVIAL_FIELD:%.*]] = struct_extract [[ARG]] : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
// CHECK: apply [[FUNC]]([[NON_TRIVIAL_FIELD]], [[TRIVIAL_FIELD2]], [[TRIVIAL_FIELD1]])
|
|
sil @big_arg_with_one_nontrivial_use_two_trivial_uses : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
%2 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x1
|
|
%3 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x2
|
|
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %4(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%intfunc = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%2) : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%3) : $@convention(thin) (Builtin.Int32) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We do not blow up the struct here since we have 4 uses, not 3.
|
|
//
|
|
// CHECK-LABEL: sil @big_arg_with_one_nontrivial_use_three_trivial_uses : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
sil @big_arg_with_one_nontrivial_use_three_trivial_uses : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
%2 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x1
|
|
%3 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x2
|
|
%3a = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.x3
|
|
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %4(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%intfunc = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%2) : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%3) : $@convention(thin) (Builtin.Int32) -> ()
|
|
apply %intfunc(%3a) : $@convention(thin) (Builtin.Int32) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// In this case, we shouldn't blow up the struct since we have not reduced the
|
|
// number of non-trivial leaf nodes used.
|
|
//
|
|
// CHECK-LABEL: sil @big_arg_with_two_nontrivial_use : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
sil @big_arg_with_two_nontrivial_use : $@convention(thin) (@guaranteed LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
%2 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k2
|
|
%3 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %3(%1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// If we have one non-trivial value that is live and only live because of a
|
|
// destroy, we can delete the argument after performing o2g.
|
|
//
|
|
// We are using a single non-trivial field of the struct. We should explode this
|
|
// so we eliminate the second non-trivial leaf.
|
|
//
|
|
// CHECK-LABEL: sil [signature_optimized_thunk] [always_inline] @big_arg_with_one_nontrivial_use_o2g_other_dead : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
// CHECK-NOT: release_value
|
|
// CHECK: apply
|
|
// CHECK-NOT: release_value
|
|
// CHECK: } // end sil function 'big_arg_with_one_nontrivial_use_o2g_other_dead'
|
|
sil @big_arg_with_one_nontrivial_use_o2g_other_dead : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
bb0(%0 : $LargeNonTrivialStructOneNonTrivialField):
|
|
%1 = struct_extract %0 : $LargeNonTrivialStructOneNonTrivialField, #LargeNonTrivialStructOneNonTrivialField.k1
|
|
release_value %1 : $Klass
|
|
%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 even though we
|
|
// aren't reducing the number of non-trivial uses. The
|
|
// funcsig_explode_heuristic_inline.sil test makes sure we in combination
|
|
// produce the appropriate SIL.
|
|
//
|
|
// We check that we can inline this correctly in the inline test.
|
|
//
|
|
// CHECK-LABEL: sil [signature_optimized_thunk] [always_inline] @big_arg_with_one_nontrivial_use_o2g : $@convention(thin) (@owned LargeNonTrivialStructOneNonTrivialField) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : $LargeNonTrivialStructOneNonTrivialField):
|
|
// CHECK: [[FUNC:%.*]] = function_ref @$s35big_arg_with_one_nontrivial_use_o2gTf4x_n : $@convention(thin) (@owned Klass, @owned Klass) -> ()
|
|
// CHECK: apply [[FUNC]](
|
|
// CHECK: } // end sil function 'big_arg_with_one_nontrivial_use_o2g'
|
|
sil @big_arg_with_one_nontrivial_use_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 : $()
|
|
}
|