File: funcsig_explode_heuristic.sil

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (207 lines) | stat: -rw-r--r-- 11,829 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// RUN: %target-sil-opt -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 : $()
}