@@ -24,7 +24,7 @@ private let verbose = false
24
24
25
25
private func log( prefix: Bool = true , _ message: @autoclosure ( ) -> String ) {
26
26
if verbose {
27
- print ( ( prefix ? " ### " : " " ) + message( ) )
27
+ debugLog ( prefix: prefix , message ( ) )
28
28
}
29
29
}
30
30
@@ -40,7 +40,10 @@ let lifetimeDependenceInsertionPass = FunctionPass(
40
40
41
41
for instruction in function. instructions {
42
42
if let dependentApply = LifetimeDependentApply ( instruction) {
43
- insertDependencies ( for: dependentApply, context)
43
+ for operand in dependentApply. applySite. parameterOperands {
44
+ insertParameterDependencies ( apply: dependentApply, target: operand, context)
45
+ }
46
+ insertResultDependencies ( for: dependentApply, context)
44
47
}
45
48
}
46
49
}
@@ -53,7 +56,7 @@ private struct LifetimeDependentApply {
53
56
guard let apply = instruction as? FullApplySite else {
54
57
return nil
55
58
}
56
- if !apply. hasResultDependence {
59
+ if !apply. hasLifetimeDependence {
57
60
return nil
58
61
}
59
62
self . applySite = apply
@@ -85,50 +88,145 @@ private struct LifetimeDependentApply {
85
88
}
86
89
87
90
extension LifetimeDependentApply {
88
- /// A lifetime argument copies, borrows, or mutatably borrows the
89
- /// lifetime of the argument value.
90
- struct LifetimeArgument {
91
+ enum TargetKind {
92
+ case result
93
+ case inParameter
94
+ case inoutParameter
95
+ case yield
96
+ case yieldAddress
97
+ }
98
+
99
+ /// A lifetime argument that either inherits or creates a new scope for the lifetime of the argument value.
100
+ struct LifetimeSource {
91
101
let convention : LifetimeDependenceConvention
92
102
let value : Value
93
103
}
94
104
95
- func getLifetimeArguments( ) -> SingleInlineArray < LifetimeArgument > {
96
- var args = SingleInlineArray < LifetimeArgument > ( )
105
+ /// List of lifetime dependencies for a single target.
106
+ struct LifetimeSources {
107
+ let targetKind : TargetKind
108
+ var sources = SingleInlineArray < LifetimeSource > ( )
109
+ }
110
+
111
+ func getResultDependenceSources( ) -> LifetimeSources ? {
112
+ guard applySite. hasResultDependence else { return nil }
113
+ var sources : LifetimeSources
114
+ switch applySite {
115
+ case let beginApply as BeginApplyInst :
116
+ if beginApply. yieldedValues. contains ( where: { $0. type. isAddress } ) {
117
+ sources = LifetimeSources ( targetKind: . yieldAddress)
118
+ } else {
119
+ sources = LifetimeSources ( targetKind: . yield)
120
+ }
121
+ default :
122
+ sources = LifetimeSources ( targetKind: . result)
123
+ }
97
124
for operand in applySite. parameterOperands {
98
125
guard let dep = applySite. resultDependence ( on: operand) else {
99
126
continue
100
127
}
101
- args. push ( LifetimeArgument ( convention: dep, value: operand. value) )
128
+ sources. sources. push ( LifetimeSource ( convention: dep, value: operand. value) )
129
+ }
130
+ return sources
131
+ }
132
+
133
+ func getParameterDependenceSources( target: Operand ) -> LifetimeSources ? {
134
+ guard let deps = applySite. parameterDependencies ( target: target) else {
135
+ return nil
136
+ }
137
+ var sources : LifetimeSources
138
+ let convention = applySite. convention ( of: target) !
139
+ switch convention {
140
+ case . indirectInout, . indirectInoutAliasable, . packInout:
141
+ sources = LifetimeSources ( targetKind: . inoutParameter)
142
+ case . indirectIn, . indirectInGuaranteed, . indirectInCXX, . directOwned, . directUnowned, . directGuaranteed,
143
+ . packOwned, . packGuaranteed:
144
+ sources = LifetimeSources ( targetKind: . inParameter)
145
+ case . indirectOut, . packOut:
146
+ debugLog ( " \( applySite) " )
147
+ fatalError ( " Lifetime dependencies cannot target \( convention) parameter " )
148
+ }
149
+ for (dep, operand) in zip ( deps, applySite. parameterOperands) {
150
+ guard let dep = dep else {
151
+ continue
152
+ }
153
+ sources. sources. push ( LifetimeSource ( convention: dep, value: operand. value) )
154
+ }
155
+ return sources
156
+ }
157
+
158
+ // Scoped dependencies require a mark_dependence for every variable that introduces this scope.
159
+ //
160
+ // Inherited dependencies do not require a mark_dependence if the target is a result or yielded value. The inherited
161
+ // lifetime is nonescapable, so either
162
+ //
163
+ // (a) the result or yield is never returned from this function
164
+ //
165
+ // (b) the inherited lifetime has a dependence root within this function (it comes from a dependent function argument
166
+ // or scoped dependence). In this case, when that depedence root is diagnosed, the analysis will find transtive uses
167
+ // of this apply's result.
168
+ //
169
+ // (c) the dependent value is passed to another call with a dependent inout argument, or it is stored to a yielded
170
+ // address of a coroutine that has a dependent inout argument. In this case, a mark_dependence will already be created
171
+ // for that inout argument.
172
+ //
173
+ // Parameter dependencies and yielded addresses always require a mark_dependence.
174
+ static func findDependenceBases( sources: LifetimeSources , _ context: FunctionPassContext ) -> [ Value ] {
175
+ var bases : [ Value ] = [ ]
176
+ for source in sources. sources {
177
+ switch source. convention {
178
+ case . inherit:
179
+ switch sources. targetKind {
180
+ case . result, . yield:
181
+ continue
182
+ case . inParameter, . inoutParameter, . yieldAddress:
183
+ _ = LifetimeDependence . visitDependenceRoots ( enclosing: source. value, context) { scope in
184
+ log ( " Inherited lifetime from \( source. value) " )
185
+ log ( " scope: \( scope) " )
186
+ bases. append ( scope. parentValue)
187
+ return . continueWalk
188
+ }
189
+ }
190
+ case . scope:
191
+ // Create a new dependence on the apply's access to the argument.
192
+ for varIntoducer in gatherVariableIntroducers ( for: source. value, context) {
193
+ if let scope = LifetimeDependence . Scope ( base: varIntoducer, context) {
194
+ log ( " Scoped lifetime from \( source. value) " )
195
+ log ( " scope: \( scope) " )
196
+ bases. append ( scope. parentValue)
197
+ }
198
+ }
199
+ }
102
200
}
103
- return args
201
+ return bases
104
202
}
105
203
}
106
204
107
205
/// If the result of this apply depends on the scope of one or more
108
206
/// arguments, then insert a mark_dependence [unresolved] from the
109
207
/// result on each argument so that the result is recognized as a
110
208
/// dependent value within each scope.
111
- private func insertDependencies( for apply: LifetimeDependentApply ,
112
- _ context: FunctionPassContext ) {
113
- let bases = findDependenceBases ( of: apply, context)
209
+ private func insertResultDependencies( for apply: LifetimeDependentApply , _ context: FunctionPassContext ) {
210
+ guard let sources = apply. getResultDependenceSources ( ) else {
211
+ return
212
+ }
213
+ log ( " Creating dependencies for \( apply. applySite) " )
214
+
215
+ let bases = LifetimeDependentApply . findDependenceBases ( sources: sources, context)
216
+
114
217
for dependentValue in apply. applySite. resultOrYields {
115
218
let builder = Builder ( before: dependentValue. nextInstruction, context)
116
- insertMarkDependencies ( value: dependentValue, initializer: nil ,
117
- bases: bases, builder: builder, context)
219
+ insertMarkDependencies ( value: dependentValue, initializer: nil , bases: bases, builder: builder, context)
118
220
}
119
221
for resultOper in apply. applySite. indirectResultOperands {
120
222
let accessBase = resultOper. value. accessBase
121
- guard let ( initialAddress, initializingStore) =
122
- accessBase. findSingleInitializer ( context) else {
223
+ guard let ( initialAddress, initializingStore) = accessBase. findSingleInitializer ( context) else {
123
224
continue
124
225
}
125
- // TODO: This is currently too strict for a diagnostic pass. We
126
- // should handle/cleanup projections and casts that occur before
127
- // the initializingStore. Or check in the SIL verifier that all
128
- // stores without an access scope follow this form. Then convert
129
- // this bail-out to an assert.
130
- guard initialAddress. usesOccurOnOrAfter ( instruction: initializingStore,
131
- context) else {
226
+ // TODO: This might bail-out on SIL that should be diagnosed. We should handle/cleanup projections and casts that
227
+ // occur before the initializingStore. Or check in the SIL verifier that all stores without an access scope follow
228
+ // this form. Then convert this bail-out to an assert.
229
+ guard initialAddress. usesOccurOnOrAfter ( instruction: initializingStore, context) else {
132
230
continue
133
231
}
134
232
assert ( initializingStore == resultOper. instruction, " an indirect result is a store " )
@@ -139,29 +237,18 @@ private func insertDependencies(for apply: LifetimeDependentApply,
139
237
}
140
238
}
141
239
142
- private func findDependenceBases( of apply: LifetimeDependentApply ,
143
- _ context: FunctionPassContext )
144
- -> [ Value ] {
240
+ private func insertParameterDependencies( apply: LifetimeDependentApply , target: Operand ,
241
+ _ context: FunctionPassContext ) {
242
+ guard let sources = apply. getParameterDependenceSources ( target: target) else {
243
+ return
244
+ }
145
245
log ( " Creating dependencies for \( apply. applySite) " )
146
- var bases : [ Value ] = [ ]
147
- for lifetimeArg in apply. getLifetimeArguments ( ) {
148
- switch lifetimeArg. convention {
149
- case . inherit:
150
- continue
151
- case . scope:
152
- // Create a new dependence on the apply's access to the argument.
153
- for varIntoducer in gatherVariableIntroducers ( for: lifetimeArg. value,
154
- context) {
155
- if let scope =
156
- LifetimeDependence . Scope ( base: varIntoducer, context) {
157
- log ( " Scoped lifetime from \( lifetimeArg. value) " )
158
- log ( " scope: \( scope) " )
159
- bases. append ( scope. parentValue)
160
- }
161
- }
162
- }
246
+
247
+ let bases = LifetimeDependentApply . findDependenceBases ( sources: sources, context)
248
+
249
+ Builder . insert ( after: apply. applySite, context) {
250
+ insertMarkDependencies ( value: target. value, initializer: nil , bases: bases, builder: $0, context)
163
251
}
164
- return bases
165
252
}
166
253
167
254
private func insertMarkDependencies( value: Value , initializer: Instruction ? ,
0 commit comments