Skip to content

Commit 490c8fa

Browse files
committed
ComputeEscapeEffects: some refactoring
Mostly source-code restructuring to make the source easier to read. NFC
1 parent 8984046 commit 490c8fa

File tree

1 file changed

+97
-99
lines changed

1 file changed

+97
-99
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEscapeEffects.swift

Lines changed: 97 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -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,11 +98,13 @@ 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)
103+
let visitor = IsExclusiveReturnEscapeVisitor(argument: arg, argumentPath: argPath, returnPath: toPath)
104+
let exclusive = visitor.isExclusiveEscape(returnInst: returnInst, context)
158105
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.
@@ -199,55 +147,105 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
199147
return false
200148
}
201149

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.
221163
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:
231171
return .abort
232-
}
233-
default:
234-
break
235172
}
236-
return .continueWalk
173+
return .ignore
237174
}
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:
243218
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
247221
}
248222
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
249248
}
249+
return .abort
250250
}
251-
let visitor = IsExclusiveReturnEscapeVisitor(fromArgument: fromArgument, fromPath: fromPath, toPath: toPath)
252-
return returnInst.operand.at(toPath).visit(using: visitor, context) ?? false
253251
}

0 commit comments

Comments
 (0)