@@ -31,10 +31,14 @@ fileprivate typealias Path = ArgumentEffect.Path
31
31
/// In future, this pass may also add other effects, like memory side effects.
32
32
let computeEffects = FunctionPass ( name: " compute-effects " , {
33
33
( function: Function , context: PassContext ) in
34
-
35
34
var argsWithDefinedEffects = getArgIndicesWithDefinedEffects ( of: function)
36
35
37
- var escapeInfo = EscapeInfo ( calleeAnalysis: context. calleeAnalysis)
36
+ struct IgnoreRecursiveCallVisitor : EscapeInfoVisitor {
37
+ func visitUse( operand: Operand , path: Path , state: State ) -> UseResult {
38
+ return isOperandOfRecursiveCall ( operand) ? . ignore : . continueWalk
39
+ }
40
+ }
41
+ var escapeInfo = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: IgnoreRecursiveCallVisitor ( ) )
38
42
var newEffects = Stack < ArgumentEffect > ( context)
39
43
let returnInst = function. returnInstruction
40
44
@@ -46,21 +50,18 @@ let computeEffects = FunctionPass(name: "compute-effects", {
46
50
if argsWithDefinedEffects. contains ( arg. index) { continue }
47
51
48
52
// First check: is the argument (or a projected value of it) escaping at all?
49
- if !escapeInfo. isEscapingWhenWalkingDown ( object: arg, path: Path ( . anything) ,
50
- visitUse: { op, _, _ in
51
- isOperandOfRecursiveCall ( op) ? . ignore : . continueWalking
52
- } ) {
53
+ if !escapeInfo. isEscapingWhenWalkingDown ( object: arg, path: Path ( . anything) ) {
53
54
let selectedArg = Selection ( arg, pathPattern: Path ( . anything) )
54
55
newEffects. push ( ArgumentEffect ( . notEscaping, selectedArg: selectedArg) )
55
56
continue
56
57
}
57
58
58
59
// Now compute effects for two important cases:
59
60
// * the argument itself + any value projections, and...
60
- if addArgEffects ( arg, argPath: Path ( ) , to: & newEffects, returnInst, & escapeInfo ) {
61
+ if addArgEffects ( context : context , arg, argPath: Path ( ) , to: & newEffects, returnInst) {
61
62
// * single class indirections
62
- _ = addArgEffects ( arg, argPath: Path ( . anyValueFields) . push ( . anyClassField) ,
63
- to: & newEffects, returnInst, & escapeInfo )
63
+ _ = addArgEffects ( context : context , arg, argPath: Path ( . anyValueFields) . push ( . anyClassField) ,
64
+ to: & newEffects, returnInst)
64
65
}
65
66
}
66
67
@@ -71,60 +72,72 @@ let computeEffects = FunctionPass(name: "compute-effects", {
71
72
newEffects. removeAll ( )
72
73
} )
73
74
75
+
74
76
/// Returns true if an argument effect was added.
75
77
private
76
- func addArgEffects( _ arg: FunctionArgument , argPath ap: Path ,
78
+ func addArgEffects( context : PassContext , _ arg: FunctionArgument , argPath ap: Path ,
77
79
to newEffects: inout Stack < ArgumentEffect > ,
78
- _ returnInst: ReturnInst ? ,
79
- _ escapeInfo: inout EscapeInfo ) -> Bool {
80
-
81
- var toSelection : Selection ?
80
+ _ returnInst: ReturnInst ? ) -> Bool {
82
81
// Correct the path if the argument is not a class reference itself, but a value type
83
82
// containing one or more references.
84
83
let argPath = arg. type. isClass ? ap : ap. push ( . anyValueFields)
85
-
86
- if escapeInfo. isEscapingWhenWalkingDown ( object: arg, path: argPath,
87
- visitUse: { op, path, followStores in
88
- if op. instruction == returnInst {
89
- // The argument escapes to the function return
90
- if followStores {
91
- // The escaping path must not introduce a followStores.
92
- return . markEscaping
93
- }
94
- if let ta = toSelection {
95
- if ta. value != . returnValue { return . markEscaping }
96
- toSelection = Selection ( . returnValue, pathPattern: path. merge ( with: ta. pathPattern) )
97
- } else {
98
- toSelection = Selection ( . returnValue, pathPattern: path)
99
- }
100
- return . ignore
101
- }
102
- if isOperandOfRecursiveCall ( op) {
103
- return . ignore
104
- }
105
- return . continueWalking
106
- } ,
107
- visitDef: { def, path, followStores in
108
- guard let destArg = def as? FunctionArgument else {
109
- return . continueWalkingUp
110
- }
111
- // The argument escapes to another argument (e.g. an out or inout argument)
112
- if followStores {
84
+
85
+ struct ArgEffectsVisitor : EscapeInfoVisitor {
86
+ init ( toSelection: Selection ? , returnInst: ReturnInst ? ) {
87
+ self . toSelection = toSelection
88
+ self . returnInst = returnInst
89
+ }
90
+
91
+ var toSelection : Selection ?
92
+ var returnInst : ReturnInst ?
93
+
94
+ mutating func visitUse( operand: Operand , path: Path , state: State ) -> UseResult {
95
+ if operand. instruction == returnInst {
96
+ // The argument escapes to the function return
97
+ if state. followStores {
113
98
// The escaping path must not introduce a followStores.
114
- return . markEscaping
99
+ return . abort
115
100
}
116
- let argIdx = destArg. index
117
101
if let ta = toSelection {
118
- if ta. value != . argument ( argIdx ) { return . markEscaping }
119
- toSelection = Selection ( . argument ( argIdx ) , pathPattern: path. merge ( with: ta. pathPattern) )
102
+ if ta. value != . returnValue { return . abort }
103
+ toSelection = Selection ( . returnValue , pathPattern: path. merge ( with: ta. pathPattern) )
120
104
} else {
121
- toSelection = Selection ( . argument ( argIdx ) , pathPattern: path)
105
+ toSelection = Selection ( . returnValue , pathPattern: path)
122
106
}
123
- return . continueWalkingDown
124
- } ) {
107
+ return . ignore
108
+ }
109
+ if isOperandOfRecursiveCall ( operand) {
110
+ return . ignore
111
+ }
112
+ return . continueWalk
113
+ }
114
+
115
+ mutating func visitDef( def: Value , path: Path , state: State ) -> DefResult {
116
+ guard let destArg = def as? FunctionArgument else {
117
+ return . continueWalkUp
118
+ }
119
+ // The argument escapes to another argument (e.g. an out or inout argument)
120
+ if state. followStores {
121
+ // The escaping path must not introduce a followStores.
122
+ return . abort
123
+ }
124
+ let argIdx = destArg. index
125
+ if let ta = toSelection {
126
+ if ta. value != . argument( argIdx) { return . abort }
127
+ toSelection = Selection ( . argument( argIdx) , pathPattern: path. merge ( with: ta. pathPattern) )
128
+ } else {
129
+ toSelection = Selection ( . argument( argIdx) , pathPattern: path)
130
+ }
131
+ return . walkDown
132
+ }
133
+ }
134
+
135
+ var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: ArgEffectsVisitor ( toSelection: nil , returnInst: returnInst) )
136
+ if walker. isEscapingWhenWalkingDown ( object: arg, path: argPath) {
125
137
return false
126
138
}
127
-
139
+
140
+ let toSelection = walker. visitor. toSelection
128
141
let fromSelection = Selection ( arg, pathPattern: argPath)
129
142
130
143
guard let toSelection = toSelection else {
@@ -137,7 +150,7 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: Path,
137
150
return false
138
151
}
139
152
140
- let exclusive = isExclusiveEscape ( fromArgument: arg, fromPath: argPath, to: toSelection, returnInst, & escapeInfo )
153
+ let exclusive = isExclusiveEscape ( context : context , fromArgument: arg, fromPath: argPath, to: toSelection, returnInst)
141
154
142
155
newEffects. push ( ArgumentEffect ( . escaping( toSelection, exclusive) , selectedArg: fromSelection) )
143
156
return true
@@ -184,52 +197,70 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
184
197
/// there are no other arguments or escape points than `fromArgument`. Also, the
185
198
/// path at the `fromArgument` must match with `fromPath`.
186
199
private
187
- func isExclusiveEscape( fromArgument: Argument , fromPath: Path , to toSelection: Selection ,
188
- _ returnInst: ReturnInst , _ escapeInfo : inout EscapeInfo ) -> Bool {
200
+ func isExclusiveEscape( context : PassContext , fromArgument: Argument , fromPath: Path , to toSelection: Selection ,
201
+ _ returnInst: ReturnInst ) -> Bool {
189
202
switch toSelection. value {
190
203
191
204
// argument -> return
192
205
case . returnValue:
193
- if escapeInfo. isEscaping (
194
- object: returnInst. operand, path: toSelection. pathPattern,
195
- visitUse: { op, path, followStores in
196
- if op. instruction == returnInst {
197
- if followStores { return . markEscaping }
198
- if path. matches ( pattern: toSelection. pathPattern) {
199
- return . ignore
200
- }
201
- return . markEscaping
202
- }
203
- return . continueWalking
204
- } ,
205
- visitDef: { def, path, followStores in
206
- guard let arg = def as? FunctionArgument else {
207
- return . continueWalkingUp
208
- }
209
- if followStores { return . markEscaping }
210
- if arg == fromArgument && path. matches ( pattern: fromPath) {
211
- return . continueWalkingDown
212
- }
213
- return . markEscaping
214
- } ) {
206
+ struct IsExclusiveReturnEscapeVisitor : EscapeInfoVisitor {
207
+ let fromArgument : Argument
208
+ let toSelection : Selection
209
+ let returnInst : ReturnInst
210
+ let fromPath : Path
211
+
212
+ mutating func visitUse( operand: Operand , path: Path , state: State ) -> UseResult {
213
+ if operand. instruction == returnInst {
214
+ if state. followStores { return . abort }
215
+ if path. matches ( pattern: toSelection. pathPattern) {
216
+ return . ignore
217
+ }
218
+ return . abort
219
+ }
220
+ return . continueWalk
221
+ }
222
+
223
+ mutating func visitDef( def: Value , path: Path , state: State ) -> DefResult {
224
+ guard let arg = def as? FunctionArgument else {
225
+ return . continueWalkUp
226
+ }
227
+ if state. followStores { return . abort }
228
+ if arg == fromArgument && path. matches ( pattern: fromPath) {
229
+ return . walkDown
230
+ }
231
+ return . abort
232
+ }
233
+ }
234
+ let visitor = IsExclusiveReturnEscapeVisitor ( fromArgument: fromArgument, toSelection: toSelection, returnInst: returnInst, fromPath: fromPath)
235
+ var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: visitor)
236
+ if walker. isEscaping ( object: returnInst. operand, path: toSelection. pathPattern) {
215
237
return false
216
238
}
217
-
218
239
// argument -> argument
219
240
case . argument( let toArgIdx) :
241
+ struct IsExclusiveArgumentEscapeVisitor : EscapeInfoVisitor {
242
+ let fromArgument : Argument
243
+ let fromPath : Path
244
+ let toSelection : Selection
245
+ let toArg : FunctionArgument
246
+
247
+ mutating func visitDef( def: Value , path: Path , state: State ) -> DefResult {
248
+ guard let arg = def as? FunctionArgument else {
249
+ return . continueWalkUp
250
+ }
251
+ if state. followStores { return . abort }
252
+ if arg == fromArgument && path. matches ( pattern: fromPath) { return . walkDown }
253
+ if arg == toArg && path. matches ( pattern: toSelection. pathPattern) { return . walkDown }
254
+ return . abort
255
+ }
256
+ }
220
257
let toArg = returnInst. function. arguments [ toArgIdx]
221
- if escapeInfo. isEscaping ( object: toArg, path: toSelection. pathPattern,
222
- visitDef: { def, path, followStores in
223
- guard let arg = def as? FunctionArgument else {
224
- return . continueWalkingUp
225
- }
226
- if followStores { return . markEscaping }
227
- if arg == fromArgument && path. matches ( pattern: fromPath) { return . continueWalkingDown }
228
- if arg == toArg && path. matches ( pattern: toSelection. pathPattern) { return . continueWalkingDown }
229
- return . markEscaping
230
- } ) {
258
+ let visitor = IsExclusiveArgumentEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath, toSelection: toSelection, toArg: toArg)
259
+ var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: visitor)
260
+ if walker. isEscaping ( object: toArg, path: toSelection. pathPattern) {
231
261
return false
232
262
}
233
263
}
234
264
return true
235
265
}
266
+
0 commit comments