@@ -124,11 +124,102 @@ let lifetimeDependenceScopeFixupPass = FunctionPass(
124
124
}
125
125
let args = scopeExtension. findArgumentDependencies ( )
126
126
127
+ // If the scope cannot be extended to the caller, this must be the outermost dependency level.
128
+ // Insert end_cow_mutation_addr if needed.
129
+ if args. isEmpty {
130
+ createEndCOWMutationIfNeeded ( lifetimeDep: newLifetimeDep, context)
131
+ }
132
+
127
133
// Redirect the dependence base to the function arguments. This may create additional mark_dependence instructions.
128
134
markDep. redirectFunctionReturn ( to: args, context)
129
135
}
130
136
}
131
137
138
+ private extension Type {
139
+ func mayHaveMutableSpan( in function: Function , _ context: FunctionPassContext ) -> Bool {
140
+ if hasArchetype {
141
+ return true
142
+ }
143
+ if isBuiltinType {
144
+ return false
145
+ }
146
+ // Only result types that are nominal can have a MutableSpan derived from an inout array access.
147
+ if nominal == nil {
148
+ return false
149
+ }
150
+ if nominal == context. swiftMutableSpan {
151
+ return true
152
+ }
153
+ if isStruct {
154
+ guard let fields = getNominalFields ( in: function) else {
155
+ return false
156
+ }
157
+ return fields. contains { $0. mayHaveMutableSpan ( in: function, context) }
158
+ }
159
+ if isTuple {
160
+ return tupleElements. contains { $0. mayHaveMutableSpan ( in: function, context) }
161
+ }
162
+ if isEnum {
163
+ guard let cases = getEnumCases ( in: function) else {
164
+ return true
165
+ }
166
+ return cases. contains { $0. payload? . mayHaveMutableSpan ( in: function, context) ?? false }
167
+ }
168
+ // Classes cannot be ~Escapable, therefore cannot hold a MutableSpan.
169
+ if isClass {
170
+ return false
171
+ }
172
+ return false
173
+ }
174
+ }
175
+
176
+ /// Insert end_cow_mutation_addr for lifetime dependent values that maybe of type MutableSpan and depend on a mutable address.
177
+ private func createEndCOWMutationIfNeeded( lifetimeDep: LifetimeDependence , _ context: FunctionPassContext ) {
178
+ var scoped : ScopedInstruction
179
+
180
+ // Handle cases which generate mutable addresses: begin_access [modify] and yield &
181
+ switch lifetimeDep. scope {
182
+ case let . access( beginAccess) :
183
+ if beginAccess. accessKind != . modify {
184
+ return
185
+ }
186
+ scoped = beginAccess
187
+ case let . yield( value) :
188
+ let beginApply = value. definingInstruction as! BeginApplyInst
189
+ if value == beginApply. token {
190
+ return
191
+ }
192
+ if beginApply. convention ( of: value as! MultipleValueInstructionResult ) != . indirectInout {
193
+ return
194
+ }
195
+ scoped = beginApply
196
+ // None of the below cases can generate a mutable address.
197
+ case let . owned:
198
+ fallthrough
199
+ case let . borrowed:
200
+ fallthrough
201
+ case let . local:
202
+ fallthrough
203
+ case let . initialized:
204
+ fallthrough
205
+ case let . caller:
206
+ fallthrough
207
+ case let . global:
208
+ fallthrough
209
+ case let . unknown:
210
+ return
211
+ }
212
+
213
+ guard lifetimeDep. dependentValue. type. mayHaveMutableSpan ( in: lifetimeDep. dependentValue. parentFunction, context) else {
214
+ return
215
+ }
216
+
217
+ for endInstruction in scoped. endInstructions {
218
+ let builder = Builder ( before: endInstruction, context)
219
+ builder. createEndCOWMutationAddr ( address: lifetimeDep. parentValue)
220
+ }
221
+ }
222
+
132
223
private extension MarkDependenceInstruction {
133
224
/// Rewrite the mark_dependence base operand to ignore inner borrow scopes (begin_borrow, load_borrow).
134
225
///
@@ -194,7 +285,7 @@ private extension MarkDependenceAddrInst {
194
285
}
195
286
}
196
287
197
- /// A scope extension is a set of nested scopes and their owners. The owner is a value that represents ownerhip of
288
+ /// A scope extension is a set of nested scopes and their owners. The owner is a value that represents ownership of
198
289
/// the outermost scopes, which cannot be extended; it limits how far the nested scopes can be extended.
199
290
private struct ScopeExtension {
200
291
let context : FunctionPassContext
0 commit comments