@@ -85,61 +85,7 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: SmallProjectionPath,
85
85
// containing one or more references.
86
86
let argPath = arg. type. isClass ? ap : ap. push ( . anyValueFields)
87
87
88
- struct ArgEffectsVisitor : EscapeVisitorWithResult {
89
- enum EscapeDestination {
90
- case notSet
91
- case toReturn( SmallProjectionPath )
92
- case toArgument( Int , SmallProjectionPath ) // argument index, path
93
- }
94
- var result = EscapeDestination . notSet
95
-
96
- mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
97
- if operand. instruction is ReturnInst {
98
- // The argument escapes to the function return
99
- if path. followStores {
100
- // The escaping path must not introduce a followStores.
101
- return . abort
102
- }
103
- switch result {
104
- case . notSet:
105
- result = . toReturn( path. projectionPath)
106
- case . toReturn( let oldPath) :
107
- result = . toReturn( oldPath. merge ( with: path. projectionPath) )
108
- case . toArgument:
109
- return . abort
110
- }
111
- return . ignore
112
- }
113
- if isOperandOfRecursiveCall ( operand) {
114
- return . ignore
115
- }
116
- return . continueWalk
117
- }
118
-
119
- mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
120
- guard let destArg = def as? FunctionArgument else {
121
- return . continueWalkUp
122
- }
123
- // The argument escapes to another argument (e.g. an out or inout argument)
124
- if path. followStores {
125
- // The escaping path must not introduce a followStores.
126
- return . abort
127
- }
128
- let argIdx = destArg. index
129
- switch result {
130
- case . notSet:
131
- result = . toArgument( argIdx, path. projectionPath)
132
- case . toArgument( let oldArgIdx, let oldPath) where oldArgIdx == argIdx:
133
- result = . toArgument( argIdx, oldPath. merge ( with: path. projectionPath) )
134
- default :
135
- return . abort
136
- }
137
- return . walkDown
138
- }
139
- }
140
-
141
- guard let result = arg. at ( argPath) . visitByWalkingDown ( using: ArgEffectsVisitor ( ) ,
142
- context) else {
88
+ guard let result = arg. at ( argPath) . visitByWalkingDown ( using: ArgEffectsVisitor ( ) , context) else {
143
89
return false
144
90
}
145
91
@@ -152,15 +98,17 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: SmallProjectionPath,
152
98
switch result {
153
99
case . notSet:
154
100
effect = EscapeEffects . ArgumentEffect ( . notEscaping, argumentIndex: arg. index, pathPattern: argPath)
101
+
155
102
case . toReturn( let toPath) :
156
- let exclusive = isExclusiveEscapeToReturn ( fromArgument : arg, fromPath : argPath,
157
- toPath : toPath , returnInst: returnInst, context)
158
- effect = EscapeEffects . ArgumentEffect ( . escapingToReturn( toPath, exclusive) ,
103
+ let visitor = IsExclusiveReturnEscapeVisitor ( argument : arg, argumentPath : argPath, returnPath : toPath )
104
+ let exclusive = visitor . isExclusiveEscape ( returnInst: returnInst, context)
105
+ effect = EscapeEffects . ArgumentEffect ( . escapingToReturn( toPath: toPath , isExclusive : exclusive) ,
159
106
argumentIndex: arg. index, pathPattern: argPath)
107
+
160
108
case . toArgument( let toArgIdx, let toPath) :
161
109
// Exclusive argument -> argument effects cannot appear because such an effect would
162
110
// involve a store which is not permitted for exclusive escapes.
163
- effect = EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgIdx, toPath, /*exclusive*/ false ) ,
111
+ effect = EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgumentIndex : toArgIdx, toPath: toPath ) ,
164
112
argumentIndex: arg. index, pathPattern: argPath)
165
113
}
166
114
newEffects. append ( effect)
@@ -176,8 +124,10 @@ private func getArgIndicesWithDefinedEscapingEffects(of function: Function) -> S
176
124
177
125
argsWithDefinedEffects. insert ( effect. argumentIndex)
178
126
switch effect. kind {
179
- case . notEscaping, . escapingToReturn: break
180
- case . escapingToArgument( let toArgIdx, _, _) : argsWithDefinedEffects. insert ( toArgIdx)
127
+ case . notEscaping, . escapingToReturn:
128
+ break
129
+ case . escapingToArgument( let toArgIdx, _) :
130
+ argsWithDefinedEffects. insert ( toArgIdx)
181
131
}
182
132
}
183
133
return argsWithDefinedEffects
@@ -197,55 +147,105 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
197
147
return false
198
148
}
199
149
200
- /// Returns true if when walking up from the `returnInst`, the `fromArgument` is the one
201
- /// and only argument which is reached - with a matching `fromPath`.
202
- private
203
- func isExclusiveEscapeToReturn( fromArgument: Argument , fromPath: SmallProjectionPath ,
204
- toPath: SmallProjectionPath ,
205
- returnInst: ReturnInst , _ context: FunctionPassContext ) -> Bool {
206
- struct IsExclusiveReturnEscapeVisitor : EscapeVisitorWithResult {
207
- let fromArgument : Argument
208
- let fromPath : SmallProjectionPath
209
- let toPath : SmallProjectionPath
210
- var result = false
211
-
212
- mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
213
- switch operand. instruction {
214
- case is ReturnInst :
215
- if path. followStores { return . abort }
216
- if path. projectionPath. matches ( pattern: toPath) {
217
- return . ignore
218
- }
150
+ private struct ArgEffectsVisitor : EscapeVisitorWithResult {
151
+ enum EscapeDestination {
152
+ case notSet
153
+ case toReturn( SmallProjectionPath )
154
+ case toArgument( Int , SmallProjectionPath ) // argument index, path
155
+ }
156
+ var result = EscapeDestination . notSet
157
+
158
+ mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
159
+ if operand. instruction is ReturnInst {
160
+ // The argument escapes to the function return
161
+ if path. followStores {
162
+ // The escaping path must not introduce a followStores.
219
163
return . abort
220
- case let si as StoringInstruction :
221
- // Don't allow store instructions because this allows the EscapeUtils to walk up
222
- // an apply result with `followStores`.
223
- if operand == si. destinationOperand {
224
- return . abort
225
- }
226
- case let ca as CopyAddrInst :
227
- // `copy_addr` is like a store.
228
- if operand == ca. destinationOperand {
164
+ }
165
+ switch result {
166
+ case . notSet:
167
+ result = . toReturn( path. projectionPath)
168
+ case . toReturn( let oldPath) :
169
+ result = . toReturn( oldPath. merge ( with: path. projectionPath) )
170
+ case . toArgument:
229
171
return . abort
230
- }
231
- default :
232
- break
233
172
}
234
- return . continueWalk
173
+ return . ignore
235
174
}
236
-
237
- mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
238
- guard let arg = def as? FunctionArgument else {
239
- return . continueWalkUp
240
- }
175
+ if isOperandOfRecursiveCall ( operand) {
176
+ return . ignore
177
+ }
178
+ return . continueWalk
179
+ }
180
+
181
+ mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
182
+ guard let destArg = def as? FunctionArgument else {
183
+ return . continueWalkUp
184
+ }
185
+ // The argument escapes to another argument (e.g. an out or inout argument)
186
+ if path. followStores {
187
+ // The escaping path must not introduce a followStores.
188
+ return . abort
189
+ }
190
+ let argIdx = destArg. index
191
+ switch result {
192
+ case . notSet:
193
+ result = . toArgument( argIdx, path. projectionPath)
194
+ case . toArgument( let oldArgIdx, let oldPath) where oldArgIdx == argIdx:
195
+ result = . toArgument( argIdx, oldPath. merge ( with: path. projectionPath) )
196
+ default :
197
+ return . abort
198
+ }
199
+ return . walkDown
200
+ }
201
+ }
202
+
203
+ /// Returns true if when walking up from the return instruction, the `fromArgument`
204
+ /// is the one and only argument which is reached - with a matching `fromPath`.
205
+ private struct IsExclusiveReturnEscapeVisitor : EscapeVisitorWithResult {
206
+ let argument : Argument
207
+ let argumentPath : SmallProjectionPath
208
+ let returnPath : SmallProjectionPath
209
+ var result = false
210
+
211
+ func isExclusiveEscape( returnInst: ReturnInst , _ context: FunctionPassContext ) -> Bool {
212
+ return returnInst. operand. at ( returnPath) . visit ( using: self , context) ?? false
213
+ }
214
+
215
+ mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
216
+ switch operand. instruction {
217
+ case is ReturnInst :
241
218
if path. followStores { return . abort }
242
- if arg == fromArgument && path. projectionPath. matches ( pattern: fromPath) {
243
- result = true
244
- return . walkDown
219
+ if path. projectionPath. matches ( pattern: returnPath) {
220
+ return . ignore
245
221
}
246
222
return . abort
223
+ case let si as StoringInstruction :
224
+ // Don't allow store instructions because this allows the EscapeUtils to walk up
225
+ // an apply result with `followStores`.
226
+ if operand == si. destinationOperand {
227
+ return . abort
228
+ }
229
+ case let ca as CopyAddrInst :
230
+ // `copy_addr` is like a store.
231
+ if operand == ca. destinationOperand {
232
+ return . abort
233
+ }
234
+ default :
235
+ break
236
+ }
237
+ return . continueWalk
238
+ }
239
+
240
+ mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
241
+ guard let arg = def as? FunctionArgument else {
242
+ return . continueWalkUp
243
+ }
244
+ if path. followStores { return . abort }
245
+ if arg == argument && path. projectionPath. matches ( pattern: argumentPath) {
246
+ result = true
247
+ return . walkDown
247
248
}
249
+ return . abort
248
250
}
249
- let visitor = IsExclusiveReturnEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath, toPath: toPath)
250
- return returnInst. operand. at ( toPath) . visit ( using: visitor, context) ?? false
251
251
}
0 commit comments