Skip to content

Commit 03e4e5c

Browse files
authored
Merge pull request #59729 from Angelogeb/apple/walkutils
Swift Optimizer: add def-use/use-def walker utilities
2 parents 77757c4 + c3ccbde commit 03e4e5c

File tree

8 files changed

+1392
-908
lines changed

8 files changed

+1392
-908
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ struct AliasAnalysis {
4545
}
4646

4747
/// Returns the correct path for address-alias functions.
48-
static func getPtrOrAddressPath(for value: Value) -> EscapeInfo.Path {
48+
static func getPtrOrAddressPath(for value: Value) -> SmallProjectionPath {
4949
let ty = value.type
5050
if ty.isAddress {
5151
// This is the regular case: the path selects any sub-fields of an address.
52-
return EscapeInfo.Path(.anyValueFields)
52+
return SmallProjectionPath(.anyValueFields)
5353
}
5454
// Some optimizations use the address-alias APIs with non-address SIL values.
5555
// TODO: this is non-intuitive and we should eliminate those API uses.
5656
if ty.isClass {
5757
// If the value is a (non-address) reference it means: all addresses within the class instance.
58-
return EscapeInfo.Path(.anyValueFields).push(.anyClassField)
58+
return SmallProjectionPath(.anyValueFields).push(.anyClassField)
5959
}
6060
// Any other non-address value means: all addresses of any referenced class instances within the value.
61-
return EscapeInfo.Path(.anyValueFields).push(.anyClassField).push(.anyValueFields)
61+
return SmallProjectionPath(.anyValueFields).push(.anyClassField).push(.anyValueFields)
6262
}
6363
}

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEffects.swift

Lines changed: 117 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ fileprivate typealias Path = ArgumentEffect.Path
3131
/// In future, this pass may also add other effects, like memory side effects.
3232
let computeEffects = FunctionPass(name: "compute-effects", {
3333
(function: Function, context: PassContext) in
34-
3534
var argsWithDefinedEffects = getArgIndicesWithDefinedEffects(of: function)
3635

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())
3842
var newEffects = Stack<ArgumentEffect>(context)
3943
let returnInst = function.returnInstruction
4044

@@ -46,21 +50,18 @@ let computeEffects = FunctionPass(name: "compute-effects", {
4650
if argsWithDefinedEffects.contains(arg.index) { continue }
4751

4852
// 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)) {
5354
let selectedArg = Selection(arg, pathPattern: Path(.anything))
5455
newEffects.push(ArgumentEffect(.notEscaping, selectedArg: selectedArg))
5556
continue
5657
}
5758

5859
// Now compute effects for two important cases:
5960
// * 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) {
6162
// * 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)
6465
}
6566
}
6667

@@ -71,60 +72,72 @@ let computeEffects = FunctionPass(name: "compute-effects", {
7172
newEffects.removeAll()
7273
})
7374

75+
7476
/// Returns true if an argument effect was added.
7577
private
76-
func addArgEffects(_ arg: FunctionArgument, argPath ap: Path,
78+
func addArgEffects(context: PassContext, _ arg: FunctionArgument, argPath ap: Path,
7779
to newEffects: inout Stack<ArgumentEffect>,
78-
_ returnInst: ReturnInst?,
79-
_ escapeInfo: inout EscapeInfo) -> Bool {
80-
81-
var toSelection: Selection?
80+
_ returnInst: ReturnInst?) -> Bool {
8281
// Correct the path if the argument is not a class reference itself, but a value type
8382
// containing one or more references.
8483
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 {
11398
// The escaping path must not introduce a followStores.
114-
return .markEscaping
99+
return .abort
115100
}
116-
let argIdx = destArg.index
117101
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))
120104
} else {
121-
toSelection = Selection(.argument(argIdx), pathPattern: path)
105+
toSelection = Selection(.returnValue, pathPattern: path)
122106
}
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) {
125137
return false
126138
}
127-
139+
140+
let toSelection = walker.visitor.toSelection
128141
let fromSelection = Selection(arg, pathPattern: argPath)
129142

130143
guard let toSelection = toSelection else {
@@ -137,7 +150,7 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: Path,
137150
return false
138151
}
139152

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)
141154

142155
newEffects.push(ArgumentEffect(.escaping(toSelection, exclusive), selectedArg: fromSelection))
143156
return true
@@ -184,52 +197,70 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
184197
/// there are no other arguments or escape points than `fromArgument`. Also, the
185198
/// path at the `fromArgument` must match with `fromPath`.
186199
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 {
189202
switch toSelection.value {
190203

191204
// argument -> return
192205
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) {
215237
return false
216238
}
217-
218239
// argument -> argument
219240
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+
}
220257
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) {
231261
return false
232262
}
233263
}
234264
return true
235265
}
266+

0 commit comments

Comments
 (0)