@@ -85,61 +85,7 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: SmallProjectionPath,
8585 // containing one or more references.
8686 let argPath = arg. type. isClass ? ap : ap. push ( . anyValueFields)
8787
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 {
14389 return false
14490 }
14591
@@ -152,15 +98,17 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: SmallProjectionPath,
15298 switch result {
15399 case . notSet:
154100 effect = EscapeEffects . ArgumentEffect ( . notEscaping, argumentIndex: arg. index, pathPattern: argPath)
101+
155102 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) ,
159106 argumentIndex: arg. index, pathPattern: argPath)
107+
160108 case . toArgument( let toArgIdx, let toPath) :
161109 // Exclusive argument -> argument effects cannot appear because such an effect would
162110 // 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 ) ,
164112 argumentIndex: arg. index, pathPattern: argPath)
165113 }
166114 newEffects. append ( effect)
@@ -176,8 +124,10 @@ private func getArgIndicesWithDefinedEscapingEffects(of function: Function) -> S
176124
177125 argsWithDefinedEffects. insert ( effect. argumentIndex)
178126 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)
181131 }
182132 }
183133 return argsWithDefinedEffects
@@ -197,55 +147,105 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
197147 return false
198148}
199149
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.
219163 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:
229171 return . abort
230- }
231- default :
232- break
233172 }
234- return . continueWalk
173+ return . ignore
235174 }
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 :
241218 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
245221 }
246222 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
247248 }
249+ return . abort
248250 }
249- let visitor = IsExclusiveReturnEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath, toPath: toPath)
250- return returnInst. operand. at ( toPath) . visit ( using: visitor, context) ?? false
251251}
0 commit comments