Skip to content

Commit c937aa0

Browse files
authored
Merge pull request swiftlang#79736 from atrick/fix-address-walk
Add verification to catch many incorrect liveness checks
2 parents eb148b1 + 19c8bd6 commit c937aa0

11 files changed

+76
-18
lines changed

include/swift/SIL/AddressUseKind.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
namespace swift {
1717

18-
enum class AddressUseKind { NonEscaping, PointerEscape, Unknown };
18+
enum class AddressUseKind { NonEscaping, Dependent, PointerEscape, Unknown };
1919

2020
inline AddressUseKind meet(AddressUseKind lhs, AddressUseKind rhs) {
2121
return (lhs > rhs) ? lhs : rhs;

include/swift/SIL/AddressWalker.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class TransitiveAddressWalker {
4848
/// Whether we could tell if this address use didn't escape, did have a
4949
/// pointer escape, or unknown if we failed to understand something.
5050
AddressUseKind result = AddressUseKind::NonEscaping;
51+
Operand *escapingUse = nullptr;
5152

5253
unsigned didInvalidate = false;
5354

@@ -83,6 +84,11 @@ class TransitiveAddressWalker {
8384
result = swift::meet(result, other);
8485
}
8586

87+
void recordEscape(Operand *op, AddressUseKind kind = AddressUseKind::PointerEscape) {
88+
meet(kind);
89+
escapingUse = op;
90+
}
91+
8692
private:
8793
/// Shim that actually calls visitUse and changes early exit.
8894
void callVisitUse(Operand *use) {
@@ -92,12 +98,16 @@ class TransitiveAddressWalker {
9298
}
9399

94100
public:
95-
AddressUseKind walk(SILValue address) &&;
101+
AddressUseKind walk(SILValue address);
102+
103+
// If the result of walk() is not NonEscaping, this returns a non-null
104+
// operand that caused the escape or unknown use.
105+
Operand *getEscapingUse() const { return escapingUse; }
96106
};
97107

98108
template <typename Impl>
99109
inline AddressUseKind
100-
TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
110+
TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) {
101111
assert(!didInvalidate);
102112

103113
// When we exit, set the result to be invalidated so we can't use this again.
@@ -155,7 +165,7 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
155165
case TermKind::CondBranchInst:
156166
// We could have an address phi. To be conservative, just treat this as
157167
// a point escape.
158-
meet(AddressUseKind::PointerEscape);
168+
recordEscape(op);
159169
for (auto succBlockArgList : ti->getSuccessorBlockArgumentLists()) {
160170
auto *succ = succBlockArgList[op->getOperandNumber()];
161171
for (auto *use : succ->getUses())
@@ -185,10 +195,13 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
185195
}
186196
}
187197

188-
// TODO: Partial apply should be NonEscaping, but then we need to consider
189-
// the apply to be a use point.
190-
if (isa<PartialApplyInst>(user) || isa<AddressToPointerInst>(user)) {
191-
meet(AddressUseKind::PointerEscape);
198+
if (isa<PartialApplyInst>(user)) {
199+
recordEscape(op, AddressUseKind::Dependent);
200+
callVisitUse(op);
201+
continue;
202+
}
203+
if (isa<AddressToPointerInst>(user)) {
204+
recordEscape(op);
192205
callVisitUse(op);
193206
continue;
194207
}
@@ -297,7 +310,7 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
297310
// address. See AddressUtils.swift. Until that is implemented, this must
298311
// be considered a pointer escape.
299312
if (op->get() == mdi->getBase()) {
300-
meet(AddressUseKind::PointerEscape);
313+
recordEscape(op, AddressUseKind::Dependent);
301314
callVisitUse(op);
302315
continue;
303316
}

include/swift/SIL/OwnershipLiveness.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ class InteriorLiveness : public OSSALiveness {
241241
public:
242242
// Summarize address uses
243243
AddressUseKind addressUseKind = AddressUseKind::Unknown;
244+
Operand *escapingUse = nullptr;
244245

245246
public:
246247
InteriorLiveness(SILValue def): OSSALiveness(def) {}

include/swift/SIL/OwnershipUseVisitor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ bool OwnershipUseVisitor<Impl>::visitInteriorPointerUses(Operand *use) {
494494
// just assumes that all scopes are incomplete.
495495
SmallVector<Operand *, 8> interiorUses;
496496
auto useKind = InteriorPointerOperand(use).findTransitiveUses(&interiorUses);
497-
if (useKind == AddressUseKind::PointerEscape) {
497+
if (useKind != AddressUseKind::NonEscaping) {
498498
if (!asImpl().handlePointerEscape(use))
499499
return false;
500500
}

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@
6161

6262
using namespace swift;
6363

64+
// FIXME: remove this option after fixing:
65+
// rdar://145994924 (Mem2Reg calls lifetime completion without checking for
66+
// pointer escapes)
67+
llvm::cl::opt<bool> VerifyLifetimeCompletion(
68+
"verify-lifetime-completion", llvm::cl::init(false),
69+
llvm::cl::desc("."));
70+
6471
static SILInstruction *endOSSALifetime(SILValue value,
6572
OSSALifetimeCompletion::LifetimeEnd end,
6673
SILBuilder &builder,
@@ -493,8 +500,16 @@ bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(
493500
}
494501
};
495502
Walker walker(*this, scopedAddress, boundary, liveness);
496-
std::move(walker).walk(scopedAddress.value);
497-
503+
AddressUseKind result = walker.walk(scopedAddress.value);
504+
if (VerifyLifetimeCompletion && boundary != Boundary::Availability
505+
&& result != AddressUseKind::NonEscaping) {
506+
llvm::errs() << "Incomplete liveness for:\n" << scopedAddress.value;
507+
if (auto *escapingUse = walker.getEscapingUse()) {
508+
llvm::errs() << " escapes at:\n";
509+
escapingUse->getUser()->printInContext(llvm::errs());
510+
}
511+
ASSERT(false && "caller must check for pointer escapes");
512+
}
498513
return endLifetimeAtBoundary(scopedAddress.value, liveness, boundary,
499514
deadEndBlocks);
500515
}
@@ -524,6 +539,15 @@ bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value,
524539
}
525540
InteriorLiveness liveness(value);
526541
liveness.compute(domInfo, handleInnerScope);
542+
if (VerifyLifetimeCompletion && boundary != Boundary::Availability
543+
&& liveness.getAddressUseKind() != AddressUseKind::NonEscaping) {
544+
llvm::errs() << "Incomplete liveness for: " << value;
545+
if (auto *escapingUse = liveness.escapingUse) {
546+
llvm::errs() << " escapes at:\n";
547+
escapingUse->getUser()->printInContext(llvm::errs());
548+
}
549+
ASSERT(false && "caller must check for pointer escapes");
550+
}
527551
return endLifetimeAtBoundary(value, liveness.getLiveness(), boundary,
528552
deadEndBlocks);
529553
}

lib/SIL/Utils/OwnershipLiveness.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ struct InteriorLivenessVisitor :
150150

151151
bool handlePointerEscape(Operand *use) {
152152
interiorLiveness.addressUseKind = AddressUseKind::PointerEscape;
153+
interiorLiveness.escapingUse = use;
153154
if (!handleUsePoint(use, UseLifetimeConstraint::NonLifetimeEnding))
154155
return false;
155156

@@ -198,6 +199,9 @@ void InteriorLiveness::print(llvm::raw_ostream &OS) const {
198199
case AddressUseKind::PointerEscape:
199200
OS << "Incomplete liveness: Escaping address\n";
200201
break;
202+
case AddressUseKind::Dependent:
203+
OS << "Incomplete liveness: Dependent value\n";
204+
break;
201205
case AddressUseKind::Unknown:
202206
OS << "Incomplete liveness: Unknown address use\n";
203207
break;

lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -899,10 +899,16 @@ static SILValue tryRewriteToPartialApplyStack(
899899

900900
OrigUnmodifiedDuringClosureLifetimeWalker origUseWalker(
901901
closureLiveness, origIsUnmodifiedDuringClosureLifetime);
902-
auto walkResult = std::move(origUseWalker).walk(orig);
903-
904-
if (walkResult == AddressUseKind::Unknown ||
905-
!origIsUnmodifiedDuringClosureLifetime) {
902+
switch (origUseWalker.walk(orig)) {
903+
case AddressUseKind::NonEscaping:
904+
case AddressUseKind::Dependent:
905+
// Dependent uses are ignored because they cannot modify the original.
906+
break;
907+
case AddressUseKind::PointerEscape:
908+
case AddressUseKind::Unknown:
909+
continue;
910+
}
911+
if (!origIsUnmodifiedDuringClosureLifetime) {
906912
continue;
907913
}
908914

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3827,6 +3827,8 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
38273827

38283828
CopiedLoadBorrowEliminationState state(markedAddress->getFunction());
38293829
CopiedLoadBorrowEliminationVisitor copiedLoadBorrowEliminator(state);
3830+
// FIXME: should check AddressUseKind::NonEscaping != walk() to handle
3831+
// PointerEscape.
38303832
if (AddressUseKind::Unknown ==
38313833
std::move(copiedLoadBorrowEliminator).walk(markedAddress)) {
38323834
LLVM_DEBUG(llvm::dbgs() << "Failed copied load borrow eliminator visit: "
@@ -3869,6 +3871,8 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
38693871
RAIILLVMDebug l("main use gathering visitor");
38703872

38713873
visitor.reset(markedAddress);
3874+
// FIXME: should check walkResult != AddressUseKind::NonEscaping to handle
3875+
// PointerEscape.
38723876
if (AddressUseKind::Unknown == std::move(visitor).walk(markedAddress)) {
38733877
LLVM_DEBUG(llvm::dbgs()
38743878
<< "Failed access path visit: " << *markedAddress);

lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ bool siloptimizer::eliminateTemporaryAllocationsFromLet(
583583
};
584584
FindCopyAddrWalker walker(copiesToVisit);
585585
std::move(walker).walk(markedInst);
586+
// FIXME: should check walk() == AddressUseKind::NonEscaping.
586587

587588
bool madeChange = false;
588589

@@ -612,6 +613,8 @@ bool siloptimizer::eliminateTemporaryAllocationsFromLet(
612613
nextCAI = nullptr;
613614
SimpleTemporaryAllocStackElimVisitor visitor(state, cai, nextCAI);
614615

616+
// FIXME: should check AddressUseKind::NonEscaping != walk() to handle
617+
// PointerEscape.
615618
if (AddressUseKind::Unknown == std::move(visitor).walk(cai->getDest()))
616619
return false;
617620

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ void swift::insertDeallocOfCapturedArguments(
15981598
SmallVector<Operand *, 2> uses;
15991599
auto useFinding = findTransitiveUsesForAddress(asi, &uses);
16001600
InstructionSet users(asi->getFunction());
1601-
if (useFinding != AddressUseKind::Unknown) {
1601+
if (useFinding == AddressUseKind::NonEscaping) {
16021602
for (auto use : uses) {
16031603
users.insert(use->getUser());
16041604
}
@@ -1609,7 +1609,7 @@ void swift::insertDeallocOfCapturedArguments(
16091609
if (isa<UnreachableInst>(terminator))
16101610
continue;
16111611
SILInstruction *insertionPoint = nullptr;
1612-
if (useFinding != AddressUseKind::Unknown) {
1612+
if (useFinding == AddressUseKind::NonEscaping) {
16131613
insertionPoint = &block->front();
16141614
for (auto &instruction : llvm::reverse(*block)) {
16151615
if (users.contains(&instruction)) {
@@ -2463,6 +2463,7 @@ SILValue swift::getInitOfTemporaryAllocStack(AllocStackInst *asi) {
24632463

24642464
AddressWalkerState state(asi->getFunction());
24652465
AddressWalker walker(state);
2466+
// Note: ignore pointer escapes for the purpose of finding initializers.
24662467
if (std::move(walker).walk(asi) == AddressUseKind::Unknown ||
24672468
state.foundError)
24682469
return SILValue();

0 commit comments

Comments
 (0)