Skip to content

Commit e8af007

Browse files
committed
Remove adjacent phis from OwnershipLiveness.
The extra complexity for traversing phis is not needed now that it handles borrowed-from instructions. Remove the redundant logic because it complicates the liveness algorithm and generates confusing results.
1 parent 5864004 commit e8af007

File tree

4 files changed

+12
-168
lines changed

4 files changed

+12
-168
lines changed

include/swift/SIL/OwnershipLiveness.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,6 @@ class InteriorLiveness : public OSSALiveness {
242242
// Summarize address uses
243243
AddressUseKind addressUseKind = AddressUseKind::Unknown;
244244

245-
// Record any guaranteed phi uses that are not already enclosed by an outer
246-
// adjacent phi.
247-
SmallVector<SILValue, 8> unenclosedPhis;
248-
249245
public:
250246
InteriorLiveness(SILValue def): OSSALiveness(def) {}
251247

@@ -259,8 +255,6 @@ class InteriorLiveness : public OSSALiveness {
259255

260256
AddressUseKind getAddressUseKind() const { return addressUseKind; }
261257

262-
ArrayRef<SILValue> getUnenclosedPhis() const { return unenclosedPhis; }
263-
264258
void print(llvm::raw_ostream &OS) const;
265259
void dump() const;
266260
};

include/swift/SIL/OwnershipUseVisitor.h

Lines changed: 4 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ enum class OwnershipUseKind { LifetimeEnding, NonLifetimeEnding };
5656
///
5757
/// - 'bool handleInnerBorrow(BorrowingOperand)' (default true)
5858
///
59-
/// - 'bool handleInnerAdjacentReborrow(SILArgument *reborrow)' (default true)
60-
///
61-
/// - 'bool handleInnerReborrow(Operand *use)' (default true)
62-
///
6359
/// - 'bool handleScopedAddress(ScopedAddressValue)' (default true)
6460
///
6561
/// These may be overridden with a transformation that adds uses to the use's
@@ -89,6 +85,9 @@ class OwnershipUseVisitorBase {
8985
/// continue processing extended liveness.
9086
///
9187
/// Return true to continue visiting other uses.
88+
///
89+
/// Note: this can lead to infinite recursion if the client does not maintain
90+
/// a visited set.
9291
bool handleOuterReborrow(Operand *phiOper) { return true; }
9392

9493
/// Handle a guaranteed forwarding instruction. After the returns, this will
@@ -110,24 +109,6 @@ class OwnershipUseVisitorBase {
110109
return true;
111110
}
112111

113-
/// Handles an inner adjacent phi where ownershipDef is a phi in the same
114-
/// block.
115-
///
116-
/// If this returns true, then handleUsePoint will be called on the
117-
/// reborrow's immediate scope ending uses are visited, along with
118-
/// handleInnerBorrow for any uses that are also reborrows.
119-
bool handleInnerAdjacentReborrow(SILArgument *reborrow) {
120-
return true;
121-
}
122-
123-
/// Handle an inner reborrow. Later, the reborrow will itself be visited as a
124-
/// use, but its scope's uses will not be transitively visited. The
125-
/// implementation may track the reborrow to insert missing reborrows or to
126-
/// continue processing extended liveness.
127-
///
128-
/// Return true to continue visiting other uses.
129-
bool handleInnerReborrow(Operand *phiOper) { return true; }
130-
131112
/// If this returns true, then handleUsePoint will be called on the scope
132113
/// ending operands.
133114
///
@@ -173,8 +154,6 @@ class OwnershipUseVisitor : OwnershipUseVisitorBase<Impl> {
173154

174155
bool visitInnerBorrow(Operand *borrowingOperand);
175156

176-
bool visitInnerAdjacentReborrow(SILArgument *reborrow);
177-
178157
bool visitInnerBorrowScopeEnd(Operand *borrowEnd);
179158

180159
bool visitOwnedUse(Operand *use);
@@ -295,32 +274,15 @@ bool OwnershipUseVisitor<Impl>::visitInnerBorrow(Operand *borrowingOperand) {
295274
});
296275
}
297276

298-
template <typename Impl>
299-
bool OwnershipUseVisitor<Impl>::
300-
visitInnerAdjacentReborrow(SILArgument *reborrow) {
301-
if (!asImpl().handleInnerAdjacentReborrow(reborrow))
302-
return false;
303-
304-
return
305-
BorrowedValue(reborrow).visitLocalScopeEndingUses([&](Operand *borrowEnd) {
306-
return visitInnerBorrowScopeEnd(borrowEnd);
307-
});
308-
}
309-
310277
/// Note: borrowEnd->get() may be a borrow introducer for an inner scope, or a
311278
/// borrow scopes that does not introduce a borrowed value (begin_apply).
312279
template <typename Impl>
313280
bool OwnershipUseVisitor<Impl>::visitInnerBorrowScopeEnd(Operand *borrowEnd) {
314281
switch (borrowEnd->getOperandOwnership()) {
315282
case OperandOwnership::EndBorrow:
283+
case OperandOwnership::Reborrow:
316284
return handleUsePoint(borrowEnd, UseLifetimeConstraint::NonLifetimeEnding);
317285

318-
case OperandOwnership::Reborrow: {
319-
if (!asImpl().handleInnerReborrow(borrowEnd))
320-
return false;
321-
322-
return handleUsePoint(borrowEnd, UseLifetimeConstraint::NonLifetimeEnding);
323-
}
324286
case OperandOwnership::DestroyingConsume:
325287
case OperandOwnership::ForwardingConsume: {
326288
// partial_apply [on_stack] and mark_dependence [nonescaping] can introduce
@@ -353,17 +315,6 @@ bool OwnershipUseVisitor<Impl>::visitInnerBorrowScopeEnd(Operand *borrowEnd) {
353315
/// and treat them like inner borrows.
354316
template <typename Impl>
355317
bool OwnershipUseVisitor<Impl>::visitInteriorUses(SILValue ssaDef) {
356-
// Inner adjacent reborrows are considered inner borrow scopes.
357-
if (auto phi = SILArgument::asPhi(ssaDef)) {
358-
if (!visitInnerAdjacentPhis(phi, [&](SILArgument *innerPhi) {
359-
if (innerPhi->isGuaranteedForwarding()) {
360-
return visitGuaranteedUses(innerPhi);
361-
}
362-
return visitInnerAdjacentReborrow(innerPhi);
363-
})) {
364-
return false;
365-
}
366-
}
367318
switch (ssaDef->getOwnershipKind()) {
368319
case OwnershipKind::Owned: {
369320
for (Operand *use : ssaDef->getUses()) {

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,11 +524,6 @@ bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value,
524524
}
525525
InteriorLiveness liveness(value);
526526
liveness.compute(domInfo, handleInnerScope);
527-
// TODO: Rebuild outer adjacent phis on demand (SILGen does not currently
528-
// produce guaranteed phis). See FindEnclosingDefs &
529-
// findSuccessorDefsFromPredDefs. If no enclosing phi is found, we can create
530-
// it here and use updateSSA to recursively populate phis.
531-
assert(liveness.getUnenclosedPhis().empty());
532527
return endLifetimeAtBoundary(value, liveness.getLiveness(), boundary,
533528
deadEndBlocks);
534529
}

lib/SIL/Utils/OwnershipLiveness.cpp

Lines changed: 8 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ void LinearLiveness::compute() {
102102
LinearLivenessVisitor(*this).visitLifetimeEndingUses(ownershipDef);
103103
}
104104

105+
/// Override OwnershipUseVisitor to callback to handleInnerScopeCallback for
106+
/// nested borrow scopes. This supports lifetime completion from the inside-out.
107+
///
108+
/// By default, handleOwnedPhi and handleOuterReborrow are already treated like
109+
/// a normal lifetime-ending use.
110+
///
111+
/// By default, handleGuaranteedForwardingPhi is already treated like a normal
112+
/// non-lifetime-ending use.
105113
struct InteriorLivenessVisitor :
106114
public OwnershipUseVisitor<InteriorLivenessVisitor> {
107115

@@ -142,14 +150,7 @@ struct InteriorLivenessVisitor :
142150

143151
bool handlePointerEscape(Operand *use) {
144152
interiorLiveness.addressUseKind = AddressUseKind::PointerEscape;
145-
return true;
146-
}
147153

148-
// handleOwnedPhi and handleOuterReborrow ends the linear lifetime.
149-
// By default, they are treated like a normal lifetime-ending use.
150-
151-
bool handleGuaranteedForwardingPhi(Operand *use) {
152-
recursivelyVisitInnerGuaranteedPhi(PhiOperand(use), /*reborrow*/false);
153154
return true;
154155
}
155156

@@ -166,18 +167,6 @@ struct InteriorLivenessVisitor :
166167
return true;
167168
}
168169

169-
bool handleInnerAdjacentReborrow(SILArgument *reborrow) {
170-
if (handleInnerScopeCallback) {
171-
handleInnerScopeCallback(reborrow);
172-
}
173-
return true;
174-
}
175-
176-
bool handleInnerReborrow(Operand *phiOper) {
177-
recursivelyVisitInnerGuaranteedPhi(PhiOperand(phiOper), /*reborrow*/true);
178-
return true;
179-
}
180-
181170
/// After this returns true, handleUsePoint will be called on the scope
182171
/// ending operands.
183172
///
@@ -188,88 +177,8 @@ struct InteriorLivenessVisitor :
188177
}
189178
return true;
190179
}
191-
192-
void recursivelyVisitInnerGuaranteedPhi(PhiOperand phiOper, bool isReborrow);
193180
};
194181

195-
// Dominating ownershipDef example: handleReborrow must continue visiting phi
196-
// uses:
197-
//
198-
// bb0:
199-
// d1 = ...
200-
// cond_br bb1, bb2
201-
// bb1:
202-
// b1 = borrow d1
203-
// br bb3(b1)
204-
// bb2:
205-
// b2 = borrow d1
206-
// br bb3(b2)
207-
// bb3(reborrow):
208-
// u1 = d1
209-
// u2 = reborrow
210-
// // can't move destroy above u2
211-
// destroy_value d1
212-
//
213-
// Dominating ownershipDef example: handleGuaranteedForwardingPhi must continue
214-
// visiting phi uses:
215-
//
216-
// bb0:
217-
// b1 = borrow d1
218-
// cond_br bb1, bb2
219-
// bb1:
220-
// p1 = projection b1
221-
// br bb3(p1)
222-
// bb2:
223-
// p1 = projection b1
224-
// br bb3(p2)
225-
// bb3(forwardingPhi):
226-
// u1 = b1
227-
// u2 = forwardingPhi
228-
// // can't move end_borrow above u2
229-
// end_borrow b1
230-
//
231-
// TODO: when phi's have a reborrow flag, remove \p isReborrow.
232-
void InteriorLivenessVisitor::
233-
recursivelyVisitInnerGuaranteedPhi(PhiOperand phiOper, bool isReborrow) {
234-
SILValue phiValue = phiOper.getValue();
235-
if (!visited.insert(phiValue))
236-
return;
237-
238-
if (!visitEnclosingDefs(phiValue, [this](SILValue enclosingDef){
239-
// If the enclosing def is \p ownershipDef, return false to check
240-
// dominance.
241-
if (enclosingDef == interiorLiveness.ownershipDef)
242-
return false;
243-
244-
// Otherwise, phiValue is enclosed by an outer adjacent phi, so its scope
245-
// does not contribute to the outer liveness. This phi will be recorded as a
246-
// regular use by the visitor, and this enclosing def will be visited as
247-
// separate lifetime-ending-use use. Return true to continue checking if any
248-
// other enclosing defs do not have an outer adjacent reborrow.
249-
return true;
250-
})) {
251-
// TODO: instead of relying on Dominance, we can reformulate this algorithm
252-
// to detect redundant phis, similar to the SSAUpdater.
253-
//
254-
// At least one enclosing def is ownershipDef. If ownershipDef dominates
255-
// phiValue, then this is consistent with a well-formed linear lifetime, and
256-
// the phi's uses directly contribute to ownershipDef's liveness.
257-
if (domInfo &&
258-
domInfo->dominates(interiorLiveness.ownershipDef->getParentBlock(),
259-
phiValue->getParentBlock())) {
260-
if (isReborrow) {
261-
visitInnerBorrow(phiOper.getOperand());
262-
} else {
263-
visitInteriorUses(phiValue);
264-
}
265-
return;
266-
}
267-
// ownershipDef does not dominate this phi. Record it so the liveness
268-
// client can use this information to insert the missing outer adjacent phi.
269-
interiorLiveness.unenclosedPhis.push_back(phiValue);
270-
}
271-
}
272-
273182
void InteriorLiveness::compute(const DominanceInfo *domInfo, InnerScopeHandlerRef handleInnerScope) {
274183
liveness.initializeDef(ownershipDef);
275184
addressUseKind = AddressUseKind::NonEscaping;
@@ -291,11 +200,6 @@ void InteriorLiveness::print(llvm::raw_ostream &OS) const {
291200
OS << "Incomplete liveness: Unknown address use\n";
292201
break;
293202
}
294-
OS << "Unenclosed phis {\n";
295-
for (SILValue phi : getUnenclosedPhis()) {
296-
OS << " " << phi;
297-
}
298-
OS << "}\n";
299203
}
300204

301205
void InteriorLiveness::dump() const { print(llvm::dbgs()); }

0 commit comments

Comments
 (0)