Skip to content

Commit 9d9ca35

Browse files
Merge pull request #4879 from swiftwasm/main
[pull] swiftwasm from main
2 parents da1a8f7 + 63fdef8 commit 9d9ca35

File tree

101 files changed

+1887
-865
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+1887
-865
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEffects.swift

Lines changed: 98 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
import SIL
1414

15-
fileprivate typealias Selection = ArgumentEffect.Selection
16-
1715
/// Computes effects for function arguments.
1816
///
1917
/// For example, if an argument does not escape, adds a non-escaping effect,
@@ -50,17 +48,16 @@ let computeEffects = FunctionPass(name: "compute-effects", {
5048

5149
// First check: is the argument (or a projected value of it) escaping at all?
5250
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)))
5552
continue
5653
}
5754

5855
// Now compute effects for two important cases:
5956
// * 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) {
6158
// * 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)
6461
}
6562
}
6663

@@ -74,34 +71,35 @@ let computeEffects = FunctionPass(name: "compute-effects", {
7471

7572
/// Returns true if an argument effect was added.
7673
private
77-
func addArgEffects(context: PassContext, _ arg: FunctionArgument, argPath ap: SmallProjectionPath,
74+
func addArgEffects(_ arg: FunctionArgument, argPath ap: SmallProjectionPath,
7875
to newEffects: inout Stack<ArgumentEffect>,
79-
_ returnInst: ReturnInst?) -> Bool {
76+
_ returnInst: ReturnInst?, _ context: PassContext) -> Bool {
8077
// Correct the path if the argument is not a class reference itself, but a value type
8178
// containing one or more references.
8279
let argPath = arg.type.isClass ? ap : ap.push(.anyValueFields)
8380

8481
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
8886
}
89-
90-
var toSelection: Selection?
91-
var returnInst: ReturnInst?
87+
var result = EscapeDestination.notSet
9288

9389
mutating func visitUse(operand: Operand, path: EscapePath) -> UseResult {
94-
if operand.instruction == returnInst {
90+
if operand.instruction is ReturnInst {
9591
// The argument escapes to the function return
9692
if path.followStores {
9793
// The escaping path must not introduce a followStores.
9894
return .abort
9995
}
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
105103
}
106104
return .ignore
107105
}
@@ -121,37 +119,44 @@ func addArgEffects(context: PassContext, _ arg: FunctionArgument, argPath ap: Sm
121119
return .abort
122120
}
123121
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
129129
}
130130
return .walkDown
131131
}
132132
}
133133

134-
var walker = EscapeInfo(calleeAnalysis: context.calleeAnalysis, visitor: ArgEffectsVisitor(toSelection: nil, returnInst: returnInst))
134+
var walker = EscapeInfo(calleeAnalysis: context.calleeAnalysis, visitor: ArgEffectsVisitor())
135135
if walker.isEscapingWhenWalkingDown(object: arg, path: argPath) {
136136
return false
137137
}
138138

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-
147139
// 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 {
149141
return false
150142
}
151143

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)
155160
return true
156161
}
157162

@@ -162,17 +167,13 @@ private func getArgIndicesWithDefinedEffects(of function: Function) -> Set<Int>
162167
for effect in function.effects.argumentEffects {
163168
if effect.isDerived { continue }
164169

165-
if case .argument(let argIdx) = effect.selectedArg.value {
166-
argsWithDefinedEffects.insert(argIdx)
167-
}
170+
argsWithDefinedEffects.insert(effect.argumentIndex)
168171

169172
switch effect.kind {
170-
case .notEscaping:
173+
case .notEscaping, .escapingToReturn:
171174
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)
176177
}
177178
}
178179
return argsWithDefinedEffects
@@ -196,70 +197,64 @@ private func isOperandOfRecursiveCall(_ op: Operand) -> Bool {
196197
/// there are no other arguments or escape points than `fromArgument`. Also, the
197198
/// path at the `fromArgument` must match with `fromPath`.
198199
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 {
226210
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
229213
}
230214
return .abort
231215
}
216+
return .continueWalk
232217
}
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
254226
}
227+
return .abort
255228
}
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
261252
}
262253
}
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)
264259
}
265260

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeInfo.swift

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -601,52 +601,51 @@ fileprivate struct EscapeInfoWalker<V: EscapeInfoVisitor> : ValueDefUseWalker,
601601
apply: ApplySite, effects: FunctionEffects) -> WalkResult {
602602
var matched = false
603603
for effect in effects.argumentEffects {
604-
guard case .escaping(let to, let exclusive) = effect.kind else {
605-
continue
606-
}
607-
if effect.selectedArg.matches(.argument(calleeArgIdx), argPath.projectionPath) {
608-
matched = true
609-
610-
switch to.value {
611-
case .returnValue:
612-
guard let fas = apply as? FullApplySite, let result = fas.singleDirectResult else { return isEscaping }
613-
614-
let p = Path(projectionPath: to.pathPattern, followStores: false, knownType: exclusive ? argPath.knownType : nil)
615-
616-
if walkDownUses(ofValue: result, path: p) == .abortWalk {
617-
return .abortWalk
618-
}
619-
case .argument(let toArgIdx):
604+
switch effect.kind {
605+
case .escapingToArgument(let toArgIdx, let toPath, let exclusive):
606+
if effect.matches(calleeArgIdx, argPath.projectionPath) {
620607
guard let callerToIdx = apply.callerArgIndex(calleeArgIndex: toArgIdx) else {
621608
return isEscaping
622609
}
623610

624611
// Continue at the destination of an arg-to-arg escape.
625612
let arg = apply.arguments[callerToIdx]
626613

627-
let p = Path(projectionPath: to.pathPattern, followStores: false, knownType: nil)
614+
let p = Path(projectionPath: toPath, followStores: false, knownType: nil)
628615
if walkUp(addressOrValue: arg, path: p) == .abortWalk {
629616
return .abortWalk
630617
}
631-
}
632-
continue
633-
}
634-
// Handle the reverse direction of an arg-to-arg escape.
635-
if to.matches(.argument(calleeArgIdx), argPath.projectionPath) {
636-
guard let callerArgIdx = apply.callerArgIndex(calleeArgIndex: effect.selectedArg.argumentIndex) else {
637-
return isEscaping
638-
}
639-
if !exclusive { return isEscaping }
618+
matched = true
619+
} else if toArgIdx == calleeArgIdx && argPath.projectionPath.matches(pattern: toPath) {
620+
// Handle the reverse direction of an arg-to-arg escape.
621+
guard let callerArgIdx = apply.callerArgIndex(calleeArgIndex: effect.argumentIndex) else {
622+
return isEscaping
623+
}
624+
if !exclusive { return isEscaping }
640625

641-
matched = true
642-
643-
let arg = apply.arguments[callerArgIdx]
644-
let p = Path(projectionPath: effect.selectedArg.pathPattern, followStores: false, knownType: nil)
626+
let arg = apply.arguments[callerArgIdx]
627+
let p = Path(projectionPath: effect.pathPattern, followStores: false, knownType: nil)
645628

646-
if walkUp(addressOrValue: arg, path: p) == .abortWalk {
647-
return .abortWalk
629+
if walkUp(addressOrValue: arg, path: p) == .abortWalk {
630+
return .abortWalk
631+
}
632+
matched = true
648633
}
649-
continue
634+
case .escapingToReturn(let toPath, let exclusive):
635+
if effect.matches(calleeArgIdx, argPath.projectionPath) {
636+
guard let fas = apply as? FullApplySite, let result = fas.singleDirectResult else {
637+
return isEscaping
638+
}
639+
640+
let p = Path(projectionPath: toPath, followStores: false, knownType: exclusive ? argPath.knownType : nil)
641+
642+
if walkDownUses(ofValue: result, path: p) == .abortWalk {
643+
return .abortWalk
644+
}
645+
matched = true
646+
}
647+
default:
648+
break
650649
}
651650
}
652651
if !matched { return isEscaping }
@@ -765,17 +764,17 @@ fileprivate struct EscapeInfoWalker<V: EscapeInfoVisitor> : ValueDefUseWalker,
765764
var matched = false
766765
for effect in callee.effects.argumentEffects {
767766
switch effect.kind {
768-
case .notEscaping:
767+
case .notEscaping, .escapingToArgument:
769768
break
770-
case .escaping(let toSelectedArg, let exclusive):
771-
if exclusive && toSelectedArg.matches(.returnValue, path.projectionPath) {
772-
matched = true
773-
let arg = apply.arguments[effect.selectedArg.argumentIndex]
769+
case .escapingToReturn(let toPath, let exclusive):
770+
if exclusive && path.projectionPath.matches(pattern: toPath) {
771+
let arg = apply.arguments[effect.argumentIndex]
774772

775-
let p = Path(projectionPath: effect.selectedArg.pathPattern, followStores: path.followStores, knownType: nil)
773+
let p = Path(projectionPath: effect.pathPattern, followStores: path.followStores, knownType: nil)
776774
if walkUp(addressOrValue: arg, path: p) == .abortWalk {
777775
return .abortWalk
778776
}
777+
matched = true
779778
}
780779
}
781780
}

0 commit comments

Comments
 (0)