12
12
13
13
import SIL
14
14
15
- fileprivate typealias Selection = ArgumentEffect . Selection
16
-
17
15
/// Computes effects for function arguments.
18
16
///
19
17
/// For example, if an argument does not escape, adds a non-escaping effect,
@@ -50,17 +48,16 @@ let computeEffects = FunctionPass(name: "compute-effects", {
50
48
51
49
// First check: is the argument (or a projected value of it) escaping at all?
52
50
if !escapeInfo. isEscapingWhenWalkingDown ( object: arg, path: SmallProjectionPath ( . anything) ) {
53
- let selectedArg = Selection ( arg, pathPattern: SmallProjectionPath ( . anything) )
54
- newEffects. push ( ArgumentEffect ( . notEscaping, selectedArg: selectedArg) )
51
+ newEffects. push ( ArgumentEffect ( . notEscaping, argumentIndex: arg. index, pathPattern: SmallProjectionPath ( . anything) ) )
55
52
continue
56
53
}
57
54
58
55
// Now compute effects for two important cases:
59
56
// * the argument itself + any value projections, and...
60
- if addArgEffects ( context : context , arg, argPath: SmallProjectionPath ( ) , to: & newEffects, returnInst) {
57
+ if addArgEffects ( arg, argPath: SmallProjectionPath ( ) , to: & newEffects, returnInst, context ) {
61
58
// * single class indirections
62
- _ = addArgEffects ( context : context , arg, argPath: SmallProjectionPath ( . anyValueFields) . push ( . anyClassField) ,
63
- to: & newEffects, returnInst)
59
+ _ = addArgEffects ( arg, argPath: SmallProjectionPath ( . anyValueFields) . push ( . anyClassField) ,
60
+ to: & newEffects, returnInst, context )
64
61
}
65
62
}
66
63
@@ -74,34 +71,35 @@ let computeEffects = FunctionPass(name: "compute-effects", {
74
71
75
72
/// Returns true if an argument effect was added.
76
73
private
77
- func addArgEffects( context : PassContext , _ arg: FunctionArgument , argPath ap: SmallProjectionPath ,
74
+ func addArgEffects( _ arg: FunctionArgument , argPath ap: SmallProjectionPath ,
78
75
to newEffects: inout Stack < ArgumentEffect > ,
79
- _ returnInst: ReturnInst ? ) -> Bool {
76
+ _ returnInst: ReturnInst ? , _ context : PassContext ) -> Bool {
80
77
// Correct the path if the argument is not a class reference itself, but a value type
81
78
// containing one or more references.
82
79
let argPath = arg. type. isClass ? ap : ap. push ( . anyValueFields)
83
80
84
81
struct ArgEffectsVisitor : EscapeInfoVisitor {
85
- init ( toSelection: Selection ? , returnInst: ReturnInst ? ) {
86
- self . toSelection = toSelection
87
- self . returnInst = returnInst
82
+ enum EscapeDestination {
83
+ case notSet
84
+ case toReturn( SmallProjectionPath )
85
+ case toArgument( Int , SmallProjectionPath ) // argument index, path
88
86
}
89
-
90
- var toSelection : Selection ?
91
- var returnInst : ReturnInst ?
87
+ var result = EscapeDestination . notSet
92
88
93
89
mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
94
- if operand. instruction == returnInst {
90
+ if operand. instruction is ReturnInst {
95
91
// The argument escapes to the function return
96
92
if path. followStores {
97
93
// The escaping path must not introduce a followStores.
98
94
return . abort
99
95
}
100
- if let ta = toSelection {
101
- if ta. value != . returnValue { return . abort }
102
- toSelection = Selection ( . returnValue, pathPattern: path. projectionPath. merge ( with: ta. pathPattern) )
103
- } else {
104
- toSelection = Selection ( . returnValue, pathPattern: path. projectionPath)
96
+ switch result {
97
+ case . notSet:
98
+ result = . toReturn( path. projectionPath)
99
+ case . toReturn( let oldPath) :
100
+ result = . toReturn( oldPath. merge ( with: path. projectionPath) )
101
+ case . toArgument:
102
+ return . abort
105
103
}
106
104
return . ignore
107
105
}
@@ -121,37 +119,44 @@ func addArgEffects(context: PassContext, _ arg: FunctionArgument, argPath ap: Sm
121
119
return . abort
122
120
}
123
121
let argIdx = destArg. index
124
- if let ta = toSelection {
125
- if ta. value != . argument( argIdx) { return . abort }
126
- toSelection = Selection ( . argument( argIdx) , pathPattern: path. projectionPath. merge ( with: ta. pathPattern) )
127
- } else {
128
- toSelection = Selection ( . argument( argIdx) , pathPattern: path. projectionPath)
122
+ switch result {
123
+ case . notSet:
124
+ result = . toArgument( argIdx, path. projectionPath)
125
+ case . toArgument( let oldArgIdx, let oldPath) where oldArgIdx == argIdx:
126
+ result = . toArgument( argIdx, oldPath. merge ( with: path. projectionPath) )
127
+ default :
128
+ return . abort
129
129
}
130
130
return . walkDown
131
131
}
132
132
}
133
133
134
- var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: ArgEffectsVisitor ( toSelection : nil , returnInst : returnInst ) )
134
+ var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: ArgEffectsVisitor ( ) )
135
135
if walker. isEscapingWhenWalkingDown ( object: arg, path: argPath) {
136
136
return false
137
137
}
138
138
139
- let toSelection = walker. visitor. toSelection
140
- let fromSelection = Selection ( arg, pathPattern: argPath)
141
-
142
- guard let toSelection = toSelection else {
143
- newEffects. push ( ArgumentEffect ( . notEscaping, selectedArg: fromSelection) )
144
- return true
145
- }
146
-
147
139
// If the function never returns, the argument can not escape to another arg/return.
148
- guard let returnInst = returnInst else {
140
+ guard let returnInst = arg . function . returnInstruction else {
149
141
return false
150
142
}
151
143
152
- let exclusive = isExclusiveEscape ( context: context, fromArgument: arg, fromPath: argPath, to: toSelection, returnInst)
153
-
154
- newEffects. push ( ArgumentEffect ( . escaping( toSelection, exclusive) , selectedArg: fromSelection) )
144
+ let effect : ArgumentEffect
145
+ switch walker. visitor. result {
146
+ case . notSet:
147
+ effect = ArgumentEffect ( . notEscaping, argumentIndex: arg. index, pathPattern: argPath)
148
+ case . toReturn( let toPath) :
149
+ let exclusive = isExclusiveEscapeToReturn ( fromArgument: arg, fromPath: argPath,
150
+ toPath: toPath, returnInst: returnInst, context)
151
+ effect = ArgumentEffect ( . escapingToReturn( toPath, exclusive) ,
152
+ argumentIndex: arg. index, pathPattern: argPath)
153
+ case . toArgument( let toArgIdx, let toPath) :
154
+ let exclusive = isExclusiveEscapeToArgument ( fromArgument: arg, fromPath: argPath,
155
+ toArgumentIndex: toArgIdx, toPath: toPath, context)
156
+ effect = ArgumentEffect ( . escapingToArgument( toArgIdx, toPath, exclusive) ,
157
+ argumentIndex: arg. index, pathPattern: argPath)
158
+ }
159
+ newEffects. push ( effect)
155
160
return true
156
161
}
157
162
@@ -162,17 +167,13 @@ private func getArgIndicesWithDefinedEffects(of function: Function) -> Set<Int>
162
167
for effect in function. effects. argumentEffects {
163
168
if effect. isDerived { continue }
164
169
165
- if case . argument( let argIdx) = effect. selectedArg. value {
166
- argsWithDefinedEffects. insert ( argIdx)
167
- }
170
+ argsWithDefinedEffects. insert ( effect. argumentIndex)
168
171
169
172
switch effect. kind {
170
- case . notEscaping:
173
+ case . notEscaping, . escapingToReturn :
171
174
break
172
- case . escaping( let to, _) :
173
- if case . argument( let toArgIdx) = to. value {
174
- argsWithDefinedEffects. insert ( toArgIdx)
175
- }
175
+ case . escapingToArgument( let toArgIdx, _, _) :
176
+ argsWithDefinedEffects. insert ( toArgIdx)
176
177
}
177
178
}
178
179
return argsWithDefinedEffects
@@ -196,70 +197,64 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
196
197
/// there are no other arguments or escape points than `fromArgument`. Also, the
197
198
/// path at the `fromArgument` must match with `fromPath`.
198
199
private
199
- func isExclusiveEscape( context: PassContext , fromArgument: Argument , fromPath: SmallProjectionPath , to toSelection: Selection ,
200
- _ returnInst: ReturnInst ) -> Bool {
201
- switch toSelection. value {
202
-
203
- // argument -> return
204
- case . returnValue:
205
- struct IsExclusiveReturnEscapeVisitor : EscapeInfoVisitor {
206
- let fromArgument : Argument
207
- let toSelection : Selection
208
- let returnInst : ReturnInst
209
- let fromPath : SmallProjectionPath
210
-
211
- mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
212
- if operand. instruction == returnInst {
213
- if path. followStores { return . abort }
214
- if path. projectionPath. matches ( pattern: toSelection. pathPattern) {
215
- return . ignore
216
- }
217
- return . abort
218
- }
219
- return . continueWalk
220
- }
221
-
222
- mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
223
- guard let arg = def as? FunctionArgument else {
224
- return . continueWalkUp
225
- }
200
+ func isExclusiveEscapeToReturn( fromArgument: Argument , fromPath: SmallProjectionPath ,
201
+ toPath: SmallProjectionPath ,
202
+ returnInst: ReturnInst , _ context: PassContext ) -> Bool {
203
+ struct IsExclusiveReturnEscapeVisitor : EscapeInfoVisitor {
204
+ let fromArgument : Argument
205
+ let fromPath : SmallProjectionPath
206
+ let toPath : SmallProjectionPath
207
+
208
+ mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
209
+ if operand. instruction is ReturnInst {
226
210
if path. followStores { return . abort }
227
- if arg == fromArgument && path. projectionPath. matches ( pattern: fromPath ) {
228
- return . walkDown
211
+ if path. projectionPath. matches ( pattern: toPath ) {
212
+ return . ignore
229
213
}
230
214
return . abort
231
215
}
216
+ return . continueWalk
232
217
}
233
- let visitor = IsExclusiveReturnEscapeVisitor ( fromArgument: fromArgument, toSelection: toSelection, returnInst: returnInst, fromPath: fromPath)
234
- var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: visitor)
235
- if walker. isEscaping ( object: returnInst. operand, path: toSelection. pathPattern) {
236
- return false
237
- }
238
- // argument -> argument
239
- case . argument( let toArgIdx) :
240
- struct IsExclusiveArgumentEscapeVisitor : EscapeInfoVisitor {
241
- let fromArgument : Argument
242
- let fromPath : SmallProjectionPath
243
- let toSelection : Selection
244
- let toArg : FunctionArgument
245
-
246
- mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
247
- guard let arg = def as? FunctionArgument else {
248
- return . continueWalkUp
249
- }
250
- if path. followStores { return . abort }
251
- if arg == fromArgument && path. projectionPath. matches ( pattern: fromPath) { return . walkDown }
252
- if arg == toArg && path. projectionPath. matches ( pattern: toSelection. pathPattern) { return . walkDown }
253
- return . abort
218
+
219
+ mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
220
+ guard let arg = def as? FunctionArgument else {
221
+ return . continueWalkUp
222
+ }
223
+ if path. followStores { return . abort }
224
+ if arg == fromArgument && path. projectionPath. matches ( pattern: fromPath) {
225
+ return . walkDown
254
226
}
227
+ return . abort
255
228
}
256
- let toArg = returnInst. function. arguments [ toArgIdx]
257
- let visitor = IsExclusiveArgumentEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath, toSelection: toSelection, toArg: toArg)
258
- var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: visitor)
259
- if walker. isEscaping ( object: toArg, path: toSelection. pathPattern) {
260
- return false
229
+ }
230
+ let visitor = IsExclusiveReturnEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath, toPath: toPath)
231
+ var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: visitor)
232
+ return !walker. isEscaping ( object: returnInst. operand, path: toPath)
233
+ }
234
+
235
+ private
236
+ func isExclusiveEscapeToArgument( fromArgument: Argument , fromPath: SmallProjectionPath ,
237
+ toArgumentIndex: Int , toPath: SmallProjectionPath , _ context: PassContext ) -> Bool {
238
+ struct IsExclusiveArgumentEscapeVisitor : EscapeInfoVisitor {
239
+ let fromArgument : Argument
240
+ let fromPath : SmallProjectionPath
241
+ let toArgumentIndex : Int
242
+ let toPath : SmallProjectionPath
243
+
244
+ mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
245
+ guard let arg = def as? FunctionArgument else {
246
+ return . continueWalkUp
247
+ }
248
+ if path. followStores { return . abort }
249
+ if arg == fromArgument && path. projectionPath. matches ( pattern: fromPath) { return . walkDown }
250
+ if arg. index == toArgumentIndex && path. projectionPath. matches ( pattern: toPath) { return . walkDown }
251
+ return . abort
261
252
}
262
253
}
263
- return true
254
+ let visitor = IsExclusiveArgumentEscapeVisitor ( fromArgument: fromArgument, fromPath: fromPath,
255
+ toArgumentIndex: toArgumentIndex, toPath: toPath)
256
+ var walker = EscapeInfo ( calleeAnalysis: context. calleeAnalysis, visitor: visitor)
257
+ let toArg = fromArgument. function. arguments [ toArgumentIndex]
258
+ return !walker. isEscaping ( object: toArg, path: toPath)
264
259
}
265
260
0 commit comments