@@ -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,11 +98,13 @@ 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)
103
+ let visitor = IsExclusiveReturnEscapeVisitor ( argument : arg, argumentPath : argPath, returnPath : toPath )
104
+ let exclusive = visitor . isExclusiveEscape ( returnInst: returnInst, context)
158
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.
@@ -199,55 +147,105 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
199
147
return false
200
148
}
201
149
202
- /// Returns true if when walking up from the `returnInst`, the `fromArgument` is the one
203
- /// and only argument which is reached - with a matching `fromPath`.
204
- private
205
- func isExclusiveEscapeToReturn( fromArgument: Argument , fromPath: SmallProjectionPath ,
206
- toPath: SmallProjectionPath ,
207
- returnInst: ReturnInst , _ context: FunctionPassContext ) -> Bool {
208
- struct IsExclusiveReturnEscapeVisitor : EscapeVisitorWithResult {
209
- let fromArgument : Argument
210
- let fromPath : SmallProjectionPath
211
- let toPath : SmallProjectionPath
212
- var result = false
213
-
214
- mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
215
- switch operand. instruction {
216
- case is ReturnInst :
217
- if path. followStores { return . abort }
218
- if path. projectionPath. matches ( pattern: toPath) {
219
- return . ignore
220
- }
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.
221
163
return . abort
222
- case let si as StoringInstruction :
223
- // Don't allow store instructions because this allows the EscapeUtils to walk up
224
- // an apply result with `followStores`.
225
- if operand == si. destinationOperand {
226
- return . abort
227
- }
228
- case let ca as CopyAddrInst :
229
- // `copy_addr` is like a store.
230
- 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:
231
171
return . abort
232
- }
233
- default :
234
- break
235
172
}
236
- return . continueWalk
173
+ return . ignore
237
174
}
238
-
239
- mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
240
- guard let arg = def as? FunctionArgument else {
241
- return . continueWalkUp
242
- }
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 :
243
218
if path. followStores { return . abort }
244
- if arg == fromArgument && path. projectionPath. matches ( pattern: fromPath) {
245
- result = true
246
- return . walkDown
219
+ if path. projectionPath. matches ( pattern: returnPath) {
220
+ return . ignore
247
221
}
248
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
249
248
}
249
+ return . abort
250
250
}
251
- let visitor = IsExclusiveReturnEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath, toPath: toPath)
252
- return returnInst. operand. at ( toPath) . visit ( using: visitor, context) ?? false
253
251
}
0 commit comments