Skip to content

Commit ac457ab

Browse files
committed
LifetimeDependenceUseDefWalker: track the owner of the value.
1 parent e976243 commit ac457ab

File tree

2 files changed

+71
-46
lines changed

2 files changed

+71
-46
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,42 +93,46 @@ func findPointerEscapingUse(of value: Value) -> Bool {
9393
/// such as "escaping" or "lexical". It must be precise for
9494
/// correctness and is performance critical.
9595
protocol ForwardingUseDefWalker {
96-
mutating func introducer(_ value: Value) -> WalkResult
96+
associatedtype PathContext
97+
98+
mutating func introducer(_ value: Value, _ path: PathContext) -> WalkResult
9799

98100
// Minimally, check a ValueSet. This walker may traverse chains of
99101
// aggregation and destructuring along with phis.
100-
mutating func needWalk(for value: Value) -> Bool
102+
mutating func needWalk(for value: Value, _ path: PathContext) -> Bool
101103

102-
mutating func walkUp(value: Value) -> WalkResult
104+
mutating func walkUp(value: Value, _ path: PathContext) -> WalkResult
103105
}
104106

105107
extension ForwardingUseDefWalker {
106-
mutating func walkUp(value: Value) -> WalkResult {
107-
walkUpDefault(forwarded: value)
108+
mutating func walkUp(value: Value, _ path: PathContext) -> WalkResult {
109+
walkUpDefault(forwarded: value, path)
108110
}
109-
mutating func walkUpDefault(forwarded value: Value) -> WalkResult {
111+
mutating func walkUpDefault(forwarded value: Value, _ path: PathContext)
112+
-> WalkResult {
110113
if let inst = value.forwardingInstruction {
111-
return walkUp(instruction: inst)
114+
return walkUp(instruction: inst, path)
112115
}
113116
if let phi = Phi(value) {
114-
return walkUp(phi: phi)
117+
return walkUp(phi: phi, path)
115118
}
116-
return introducer(value)
119+
return introducer(value, path)
117120
}
118-
mutating func walkUp(instruction: ForwardingInstruction) -> WalkResult {
121+
mutating func walkUp(instruction: ForwardingInstruction, _ path: PathContext)
122+
-> WalkResult {
119123
for operand in instruction.forwardedOperands {
120-
if needWalk(for: operand.value) {
121-
if walkUp(value: operand.value) == .abortWalk {
124+
if needWalk(for: operand.value, path) {
125+
if walkUp(value: operand.value, path) == .abortWalk {
122126
return .abortWalk
123127
}
124128
}
125129
}
126130
return .continueWalk
127131
}
128-
mutating func walkUp(phi: Phi) -> WalkResult {
132+
mutating func walkUp(phi: Phi, _ path: PathContext) -> WalkResult {
129133
for operand in phi.incomingOperands {
130-
if needWalk(for: operand.value) {
131-
if walkUp(value: operand.value) == .abortWalk {
134+
if needWalk(for: operand.value, path) {
135+
if walkUp(value: operand.value, path) == .abortWalk {
132136
return .abortWalk
133137
}
134138
}
@@ -146,7 +150,7 @@ func gatherLifetimeIntroducers(for value: Value, _ context: Context) -> [Value]
146150
return .continueWalk
147151
}
148152
defer { walker.deinitialize() }
149-
_ = walker.walkUp(value: value)
153+
_ = walker.walkUp(value: value, ())
150154
return introducers
151155
}
152156

@@ -156,7 +160,7 @@ func visitLifetimeIntroducers(for value: Value, _ context: Context,
156160
-> WalkResult {
157161
var walker = VisitLifetimeIntroducers(context, visitor: visitor)
158162
defer { walker.visitedValues.deinitialize() }
159-
return walker.walkUp(value: value)
163+
return walker.walkUp(value: value, ())
160164
}
161165

162166
private struct VisitLifetimeIntroducers : ForwardingUseDefWalker {
@@ -170,11 +174,11 @@ private struct VisitLifetimeIntroducers : ForwardingUseDefWalker {
170174

171175
mutating func deinitialize() { visitedValues.deinitialize() }
172176

173-
mutating func needWalk(for value: Value) -> Bool {
177+
mutating func needWalk(for value: Value, _: Void) -> Bool {
174178
visitedValues.insert(value)
175179
}
176-
177-
mutating func introducer(_ value: Value) -> WalkResult {
180+
181+
mutating func introducer(_ value: Value, _: Void) -> WalkResult {
178182
visitor(value)
179183
}
180184
}

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context) -> [Value]
5555
return .continueWalk
5656
}
5757
defer { useDefVisitor.deinitialize() }
58-
_ = useDefVisitor.walkUp(value: value)
58+
_ = useDefVisitor.walkUp(value: value, nil)
5959
return introducers
6060
}
6161

@@ -431,7 +431,8 @@ extension LifetimeDependence {
431431
-> WalkResult {
432432
var useDefVisitor = UseDefVisitor(context, visitor)
433433
defer { useDefVisitor.deinitialize() }
434-
return useDefVisitor.walkUp(value: value)
434+
let owner = value.ownership == .owned ? value : nil
435+
return useDefVisitor.walkUp(value: value, owner)
435436
}
436437

437438
private struct UseDefVisitor : LifetimeDependenceUseDefWalker {
@@ -453,7 +454,10 @@ extension LifetimeDependence {
453454
visitedValues.deinitialize()
454455
}
455456

456-
mutating func needWalk(for value: Value) -> Bool {
457+
mutating func needWalk(for value: Value, _ owner: Value?) -> Bool {
458+
// FIXME: cache the value's owner, and support walking up
459+
// multiple guaranteed forwards to different owners, then
460+
// reconverging.
457461
visitedValues.insert(value)
458462
}
459463

@@ -464,8 +468,12 @@ extension LifetimeDependence {
464468
// of an access scope. An address type mark_dependence
465469
// [nonescaping]` can only result from an indirect function result
466470
// when opaque values are not enabled.
467-
mutating func introducer(_ value: Value) -> WalkResult {
468-
guard let scope = LifetimeDependence.Scope(base: value, context)
471+
//
472+
// FIXME: Recursively handle .initialized scope by checking
473+
// findSingleStore and walking the stored value.
474+
mutating func introducer(_ value: Value, _ owner: Value?) -> WalkResult {
475+
let base = owner ?? value
476+
guard let scope = LifetimeDependence.Scope(base: base, context)
469477
else {
470478
return .continueWalk
471479
}
@@ -494,28 +502,28 @@ struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefWalker {
494502
visitedValues.deinitialize()
495503
}
496504

497-
mutating func needWalk(for value: Value) -> Bool {
505+
mutating func needWalk(for value: Value, _ owner: Value?) -> Bool {
498506
visitedValues.insert(value)
499507
}
500508

501-
mutating func introducer(_ value: Value) -> WalkResult {
509+
mutating func introducer(_ value: Value, _ owner: Value?) -> WalkResult {
502510
return visitorClosure(value)
503511
}
504512

505-
mutating func walkUp(value: Value) -> WalkResult {
513+
mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult {
506514
switch value.definingInstruction {
507515
case let moveInst as MoveValueInst:
508516
if moveInst.isFromVarDecl {
509-
return introducer(moveInst)
517+
return introducer(moveInst, owner)
510518
}
511519
case let borrow as BeginBorrowInst:
512520
if borrow.isFromVarDecl {
513-
return introducer(borrow)
521+
return introducer(borrow, owner)
514522
}
515523
default:
516524
break
517525
}
518-
return walkUpDefault(dependent: value)
526+
return walkUpDefault(dependent: value, owner: owner)
519527
}
520528
}
521529

@@ -573,20 +581,22 @@ struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefWalker {
573581
///
574582
/// Start walking:
575583
/// walkUp(value: Value) -> WalkResult
576-
protocol LifetimeDependenceUseDefWalker : ForwardingUseDefWalker {
584+
protocol LifetimeDependenceUseDefWalker : ForwardingUseDefWalker where PathContext == Value? {
577585
var context: Context { get }
578586

579-
mutating func introducer(_ value: Value) -> WalkResult
587+
mutating func introducer(_ value: Value, _ owner: Value?) -> WalkResult
580588

581-
// Minimally, check a ValueSet. This walker may traverse chains of aggregation and destructuring along with phis.
582-
mutating func needWalk(for value: Value) -> Bool
589+
// Minimally, check a ValueSet. This walker may traverse chains of
590+
// aggregation and destructuring along with phis.
591+
mutating func needWalk(for value: Value, _ owner: Value?) -> Bool
583592

584-
mutating func walkUp(value: Value) -> WalkResult
593+
mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult
585594
}
586595

596+
// Implement ForwardingUseDefWalker
587597
extension LifetimeDependenceUseDefWalker {
588-
mutating func walkUp(value: Value) -> WalkResult {
589-
walkUpDefault(dependent: value)
598+
mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult {
599+
walkUpDefault(dependent: value, owner: owner)
590600
}
591601

592602
// Extend ForwardingUseDefWalker to handle copies, moves, and
@@ -599,29 +609,40 @@ extension LifetimeDependenceUseDefWalker {
599609
//
600610
// Handles loads as a convenience so the client receives the load's
601611
// address as an introducer.
602-
mutating func walkUpDefault(dependent value: Value) -> WalkResult {
612+
mutating func walkUpDefault(dependent value: Value, owner: Value?)
613+
-> WalkResult {
603614
switch value.definingInstruction {
604615
case let copyInst as CopyValueInst:
605-
return walkUp(value: copyInst.fromValue)
616+
return walkUp(newLifetime: copyInst.fromValue)
606617
case let moveInst as MoveValueInst:
607-
return walkUp(value: moveInst.fromValue)
618+
return walkUp(value: moveInst.fromValue, owner)
608619
case let borrow as BeginBorrowInst:
609-
return walkUp(value: borrow.borrowedValue)
620+
return walkUp(newLifetime: borrow.borrowedValue)
610621
case let load as LoadInstruction:
611-
return walkUp(value: load.address)
622+
return introducer(load.address, owner)
612623
case let markDep as MarkDependenceInst:
613624
if let dependence = LifetimeDependence(markDep, context) {
614-
return walkUp(value: dependence.parentValue)
625+
let parent = dependence.parentValue
626+
if markDep.isForwarded(from: parent) {
627+
return walkUp(value: dependence.parentValue, owner)
628+
} else {
629+
return walkUp(newLifetime: dependence.parentValue)
630+
}
615631
}
616632
default:
617633
break
618634
}
619635
// If the dependence chain has a phi, consider it a root. Dependence roots
620636
// are currently expected to dominate all dependent values.
621637
if Phi(value) != nil {
622-
return introducer(value)
638+
return introducer(value, owner)
623639
}
624-
return walkUpDefault(forwarded: value)
640+
return walkUpDefault(forwarded: value, owner)
641+
}
642+
643+
private mutating func walkUp(newLifetime: Value) -> WalkResult {
644+
let newOwner = newLifetime.ownership == .owned ? newLifetime : nil
645+
return walkUp(value: newLifetime, newOwner)
625646
}
626647
}
627648

0 commit comments

Comments
 (0)