Skip to content

Commit 75ea382

Browse files
committed
Fix initial ForwardingInstruction implementation and handle phis
1 parent 7592b18 commit 75ea382

File tree

3 files changed

+88
-20
lines changed

3 files changed

+88
-20
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- OwnershipUtils.swift - Utilities for ownership -------------------===//
1+
//===--- ForwardingUtils.swift - Utilities for ownership forwarding -------===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -29,8 +29,6 @@ import SIL
2929
//
3030
// Note: Although move_value conceptually forwards an owned value, it also summarizes lifetime attributes; therefore, it is not formally a ForwardingInstruction.
3131
//
32-
// TODO: when phi lifetime flags are implemented, phis will introduce a lifetime in the same way as move_value.
33-
//
3432
// The lifetime introducer of a guaranteed value is the borrow introducer:
3533
//
3634
// # lifetime introducer / borrow introducer
@@ -43,11 +41,25 @@ import SIL
4341
//
4442
// TODO: When a begin_borrow has no lifetime flags, it can be ignored as a lifetime introducer. In that case, an owned value may introduce guaranteed OSSA lifetimes.
4543
//
44+
// Forwarded lifetimes also extend through phis. In this case, however, there is no ForwardingInstruction.
45+
//
46+
// # lifetime introducer
47+
// %1 = apply -+ -+
48+
// ... | OSSA lifetime |
49+
// # phi operand | |
50+
// br bbContinue(%1: $S) -+ | forward-extended lifetime
51+
// |
52+
// bbContinue(%phi : $S): -+ OSSA lifetime |
53+
// ... | |
54+
// destroy_value %phi -+ -+
55+
//
56+
// TODO: when phi lifetime flags are implemented, phis will introduce a lifetime in the same way as move_value.
57+
//
4658
// This walker is used to query basic lifetime attributes on values, such as "escaping" or "lexical". It must be precise for correctness and is performance critical.
4759
protocol ForwardingUseDefWalker {
4860
mutating func introducer(_ value: Value) -> WalkResult
4961

50-
// Minimally, check a ValueSet. This walker may traverse chains of aggregation and destructuring by default. Implementations may traverse phis.
62+
// Minimally, check a ValueSet. This walker may traverse chains of aggregation and destructuring along with phis.
5163
mutating func needWalk(for value: Value) -> Bool
5264

5365
mutating func walkUp(value: Value) -> WalkResult
@@ -58,10 +70,12 @@ extension ForwardingUseDefWalker {
5870
walkUpDefault(value: value)
5971
}
6072
mutating func walkUpDefault(value: Value) -> WalkResult {
61-
if let inst = value.definingInstruction as? ForwardingInstruction
62-
{
73+
if let inst = value.forwardingInstruction {
6374
return walkUp(instruction: inst)
6475
}
76+
if let phi = Phi(value) {
77+
return walkUp(phi: phi)
78+
}
6579
return introducer(value)
6680
}
6781
mutating func walkUp(instruction: ForwardingInstruction) -> WalkResult {
@@ -74,6 +88,16 @@ extension ForwardingUseDefWalker {
7488
}
7589
return .continueWalk
7690
}
91+
mutating func walkUp(phi: Phi) -> WalkResult {
92+
for operand in phi.incomingOperands {
93+
if needWalk(for: operand.value) {
94+
if walkUp(value: operand.value) == .abortWalk {
95+
return .abortWalk
96+
}
97+
}
98+
}
99+
return .continueWalk
100+
}
77101
}
78102

79103
// This conveniently gathers all forward introducers and deinitializes visitedValues before the caller has a chance to recurse.
@@ -103,14 +127,34 @@ private struct GatherLifetimeIntroducers : ForwardingUseDefWalker {
103127
}
104128
}
105129

130+
enum ForwardingUseResult: CustomStringConvertible {
131+
case operand(Operand)
132+
case deadValue(Value)
133+
134+
var description: String {
135+
switch self {
136+
case .operand(let operand):
137+
return operand.description
138+
case .deadValue(let deadValue):
139+
return "dead value: " + deadValue.description
140+
}
141+
}
142+
}
143+
106144
// Visit all the uses in a forward-extended lifetime (LifetimeIntroducer -> Operand).
107145
protocol ForwardingDefUseWalker {
108146
// Minimally, check a ValueSet. This walker may traverse chains of aggregation and destructuring by default. Implementations may handle phis.
109147
mutating func needWalk(for value: Value) -> Bool
110148

111-
mutating func leafUse(_ operand: Operand) -> WalkResult
149+
// Report any initial or forwarded with no uses. Only relevant for
150+
// guaranteed values or incomplete OSSA. This could be a dead
151+
// instruction, a terminator in which the result is dead on one
152+
// path, or a dead phi.
153+
mutating func deadValue(_: Value) -> WalkResult
154+
155+
mutating func leafUse(_: Operand) -> WalkResult
112156

113-
mutating func walkDownUses(of value: Value) -> WalkResult
157+
mutating func walkDownUses(of: Value) -> WalkResult
114158

115159
mutating func walkDown(operand: Operand) -> WalkResult
116160
}
@@ -123,10 +167,15 @@ extension ForwardingDefUseWalker {
123167
mutating func walkDownUsesDefault(of value: Value) -> WalkResult {
124168
if !needWalk(for: value) { return .continueWalk }
125169

170+
var hasUse = false
126171
for operand in value.uses where !operand.isTypeDependent {
127172
if walkDown(operand: operand) == .abortWalk {
128173
return .abortWalk
129174
}
175+
hasUse = true
176+
}
177+
if !hasUse {
178+
deadValue(value)
130179
}
131180
return .continueWalk
132181
}
@@ -139,6 +188,9 @@ extension ForwardingDefUseWalker {
139188
if let inst = operand.instruction as? ForwardingInstruction {
140189
return walkDownAllResults(of: inst)
141190
}
191+
if let phi = Phi(using: operand) {
192+
return walkDownUses(of: phi.value)
193+
}
142194
return leafUse(operand)
143195
}
144196

@@ -156,9 +208,8 @@ extension ForwardingDefUseWalker {
156208
// This conveniently allows a closure to be called for each leaf use of a forward-extended lifetime. It should be called on a forward introducer provided by ForwardingDefUseWalker.introducer() or gatherLifetimeIntroducers().
157209
//
158210
// TODO: make the visitor non-escaping once Swift supports stored non-escaping closues.
159-
func visitForwardedUses(introducer: Value,
160-
visitor: @escaping (Operand) -> WalkResult,
161-
_ context: Context)
211+
func visitForwardedUses(introducer: Value, _ context: Context,
212+
visitor: @escaping (ForwardingUseResult) -> WalkResult)
162213
-> WalkResult {
163214
var useVisitor = VisitForwardedUses(visitor: visitor, context)
164215
defer { useVisitor.visitedValues.deinitialize() }
@@ -167,9 +218,10 @@ func visitForwardedUses(introducer: Value,
167218

168219
private struct VisitForwardedUses : ForwardingDefUseWalker {
169220
var visitedValues: ValueSet
170-
var visitor: (Operand) -> WalkResult
221+
var visitor: (ForwardingUseResult) -> WalkResult
171222

172-
init(visitor: @escaping (Operand) -> WalkResult, _ context: Context) {
223+
init(visitor: @escaping (ForwardingUseResult) -> WalkResult,
224+
_ context: Context) {
173225
self.visitedValues = ValueSet(context)
174226
self.visitor = visitor
175227
}
@@ -179,6 +231,10 @@ private struct VisitForwardedUses : ForwardingDefUseWalker {
179231
}
180232

181233
mutating func leafUse(_ operand: Operand) -> WalkResult {
182-
return visitor(operand)
234+
return visitor(.operand(operand))
235+
}
236+
237+
mutating func deadValue(_ value: Value) -> WalkResult {
238+
return visitor(.deadValue(value))
183239
}
184240
}

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,19 @@ public struct Phi {
6464
guard term is BranchInst || term is CondBranchInst else { return nil }
6565
self.value = argument
6666
}
67-
67+
68+
public init?(using operand: Operand) {
69+
switch operand.instruction {
70+
case let br as BranchInst:
71+
self.init(br.getArgument(for: operand))
72+
case let condBr as CondBranchInst:
73+
guard let arg = condBr.getArgument(for: operand) else { return nil }
74+
self.init(arg)
75+
default:
76+
return nil
77+
}
78+
}
79+
6880
public var predecessors: PredecessorList {
6981
return value.parentBlock.predecessors
7082
}

SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ extension ForwardingInstruction {
7979
// See ForwardingOperation::getSingleForwardingOperand().
8080
public var singleForwardedOperand: Operand? {
8181
let definedOps = self.definedOperands
82-
assert(definedOps.count == 1);
83-
return definedOps[0];
82+
assert(definedOps.count == 1, "expected single operand for forwarding")
83+
return definedOps[0]
8484
}
8585
}
8686

@@ -117,19 +117,19 @@ extension DifferentiableFunctionInst {
117117
// Instructions with a singleForwardedOperand and additional operands.
118118

119119
extension MarkDependenceInst {
120-
public var singleForwardedOperand: Operand {
120+
public var singleForwardedOperand: Operand? {
121121
return valueOperand
122122
}
123123
}
124124

125125
extension RefToBridgeObjectInst {
126-
public var singleForwardedOperand: Operand {
126+
public var singleForwardedOperand: Operand? {
127127
return convertedOperand
128128
}
129129
}
130130

131131
extension TuplePackExtractInst {
132-
public var singleForwardedOperand: Operand {
132+
public var singleForwardedOperand: Operand? {
133133
return tupleOperand
134134
}
135135
}

0 commit comments

Comments
 (0)