Skip to content

[NFC] PrunedLiveness: Clarified boundary API. #75422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions include/swift/SIL/PrunedLiveness.h
Original file line number Diff line number Diff line change
Expand Up @@ -617,10 +617,13 @@ class PrunedLiveRange : public PrunedLiveness {
bool isAvailableOut(SILBasicBlock *block, DeadEndBlocks &deadEndBlocks) const;
bool isInstructionAvailable(SILInstruction *user,
DeadEndBlocks &deadEndBlocks) const;
/// Whether \p user is within the liveness boundary (never extended into
/// dead-end regions).
bool isWithinLivenessBoundary(SILInstruction *inst) const;
/// Whether \p user is within the boundary extended from live regions into
/// dead-end regions up to the availability boundary.
bool isWithinExtendedBoundary(SILInstruction *user,
DeadEndBlocks *deadEndBlocks) const;
DeadEndBlocks &deadEndBlocks) const;

public:
/// Add \p inst to liveness which uses the def as indicated by \p usage.
Expand Down Expand Up @@ -660,7 +663,12 @@ class PrunedLiveRange : public PrunedLiveness {

/// Check if \p inst occurs in between the definition this def and the
/// liveness boundary.
bool isWithinBoundary(SILInstruction *inst) const;
///
/// Pass \p deadEndBlocks when the defs' lifetime isn't known to be complete.
/// When passed, the liveness boundary is understood to extend into dead-end
/// regions.
bool isWithinBoundary(SILInstruction *inst,
DeadEndBlocks *deadEndBlocks) const;

/// Returns true when all \p uses are between this def and the liveness
/// boundary \p deadEndBlocks is optional.
Expand Down
3 changes: 2 additions & 1 deletion lib/SIL/Utils/OSSALifetimeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ static void visitUsersOutsideLinearLivenessBoundary(
continue;
}
auto *user = pair.first;
if (linearLiveness.getLiveness().isWithinBoundary(user)) {
if (linearLiveness.getLiveness().isWithinBoundary(
user, /*deadEndBlocks=*/nullptr)) {
continue;
}
visitor(user);
Expand Down
36 changes: 19 additions & 17 deletions lib/SIL/Utils/PrunedLiveness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ static FunctionTest SSAUseLivenessTest("ssa_use_liveness", [](auto &function,
} // end namespace swift::test

template <typename LivenessWithDefs>
bool PrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
bool PrunedLiveRange<LivenessWithDefs>::isWithinLivenessBoundary(
SILInstruction *inst) const {
assert(asImpl().isInitialized());

Expand Down Expand Up @@ -574,8 +574,18 @@ bool PrunedLiveRange<LivenessWithDefs>::isInstructionAvailable(
}

template <typename LivenessWithDefs>
bool PrunedLiveRange<LivenessWithDefs>::isWithinExtendedBoundary(
bool PrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
SILInstruction *inst, DeadEndBlocks *deadEndBlocks) const {
if (deadEndBlocks) {
return asImpl().isWithinExtendedBoundary(inst, *deadEndBlocks);
} else {
return asImpl().isWithinLivenessBoundary(inst);
}
}

template <typename LivenessWithDefs>
bool PrunedLiveRange<LivenessWithDefs>::isWithinExtendedBoundary(
SILInstruction *inst, DeadEndBlocks &deadEndBlocks) const {
// A value has a pruned live region, a live region and an available region.
// (Note: PrunedLiveness does not distinguish between the pruned live region
// and the live region; the pruned live region coincides with the live region
Expand Down Expand Up @@ -628,21 +638,13 @@ bool PrunedLiveRange<LivenessWithDefs>::isWithinExtendedBoundary(
// That this region is of interest is another result of lacking complete
// OSSA lifetimes.

if (asImpl().isWithinBoundary(inst)) {
if (asImpl().isWithinLivenessBoundary(inst)) {
// The extended region is a superset of the pruned live region.
return true;
}

if (!deadEndBlocks) {
// Without knowledge of the dead-end region, the extended region can't be
// determined. It could, of course, be rediscovered here, but that would
// be silly; instead, allowing a nullable pointer provides a mechanism for
// the client to indicate what invariants hold. Specifically, omitting
// dead-end blocks is equivalent to asserting that lifetimes are complete.
return false;
}
SILBasicBlock *parent = inst->getParent();
if (!deadEndBlocks->isDeadEnd(parent)) {
if (!deadEndBlocks.isDeadEnd(parent)) {
// The extended region intersected with the non-dead-end region is equal to
// the pruned live region.
return false;
Expand All @@ -652,7 +654,7 @@ bool PrunedLiveRange<LivenessWithDefs>::isWithinExtendedBoundary(
break;
case PrunedLiveBlocks::LiveWithin:
// Dead defs may result in LiveWithin but AvailableOut blocks.
return isInstructionAvailable(inst, *deadEndBlocks);
return isInstructionAvailable(inst, deadEndBlocks);
case PrunedLiveBlocks::LiveOut:
// The instruction is not within the boundary, but its parent is LiveOut;
// therefore it must be a def block.
Expand Down Expand Up @@ -687,7 +689,7 @@ bool PrunedLiveRange<LivenessWithDefs>::isWithinExtendedBoundary(
worklist.push(parent);
while (auto *block = worklist.pop()) {
auto isLive = liveBlocks.getBlockLiveness(block);
if (!deadEndBlocks->isDeadEnd(block)) {
if (!deadEndBlocks.isDeadEnd(block)) {
// The first block beyond the dead-end region has been reached.
if (isLive != PrunedLiveBlocks::LiveOut) {
// Cases (2) above.
Expand All @@ -706,7 +708,7 @@ bool PrunedLiveRange<LivenessWithDefs>::isWithinExtendedBoundary(
case PrunedLiveBlocks::LiveWithin:
// Availability may have ended in this block. Check whether the block is
// "AvailableOut".
if (!isAvailableOut(block, *deadEndBlocks)) {
if (!isAvailableOut(block, deadEndBlocks)) {
// Case (1) above.
return false;
}
Expand Down Expand Up @@ -799,7 +801,7 @@ bool PrunedLiveRange<LivenessWithDefs>::areUsesWithinBoundary(

for (auto *use : uses) {
auto *user = use->getUser();
if (!isWithinExtendedBoundary(user, deadEndBlocks))
if (!isWithinBoundary(user, deadEndBlocks))
return false;
}
return true;
Expand All @@ -812,7 +814,7 @@ bool PrunedLiveRange<LivenessWithDefs>::areUsesOutsideBoundary(

for (auto *use : uses) {
auto *user = use->getUser();
if (isWithinExtendedBoundary(user, deadEndBlocks))
if (isWithinBoundary(user, deadEndBlocks))
return false;
}
return true;
Expand Down
3 changes: 2 additions & 1 deletion lib/SIL/Utils/ScopedAddressUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ bool swift::hasOtherStoreBorrowsInLifetime(StoreBorrowInst *storeBorrow,

for (auto *otherStoreBorrow : otherStoreBorrows) {
// Return true, if otherStoreBorrow was in \p storeBorrow's scope
if (liveness->isWithinBoundary(otherStoreBorrow)) {
if (liveness->isWithinBoundary(otherStoreBorrow,
/*deadEndBlocks=*/nullptr)) {
return true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/Verifier/LoadBorrowImmutabilityChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ bool LoadBorrowImmutabilityAnalysis::isImmutableInScope(
continue;
}

if (borrowLiveness.isWithinBoundary(write)) {
if (borrowLiveness.isWithinBoundary(write, /*deadEndBlocks=*/nullptr)) {
llvm::errs() << "Write: " << *write;
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/Verifier/SILOwnershipVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ bool SILValueOwnershipChecker::checkDeadEnds(
}
auto allWithinBoundary = true;
for (auto *use : regularUses) {
if (!liveness.isWithinBoundary(use->getUser())) {
if (!liveness.isWithinBoundary(use->getUser(), /*deadEndBlocks=*/nullptr)) {
allWithinBoundary |= errorBuilder.handleMalformedSIL([&] {
llvm::errs()
<< "Owned value without lifetime ending uses whose regular use "
Expand Down
5 changes: 3 additions & 2 deletions lib/SIL/Verifier/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2714,7 +2714,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
LinearLiveness::DoNotIncludeExtensions);
linearLiveness.compute();
auto &liveness = linearLiveness.getLiveness();
require(!liveness.isWithinBoundary(I),
require(!liveness.isWithinBoundary(I, /*deadEndBlocks=*/nullptr),
"extend_lifetime use within unextended linear liveness boundary!?");
PrunedLivenessBoundary boundary;
liveness.computeBoundary(boundary);
Expand Down Expand Up @@ -2789,7 +2789,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
if (scopedAddress.isScopeEndingUse(use)) {
continue;
}
if (!scopedAddressLiveness->isWithinBoundary(user)) {
if (!scopedAddressLiveness->isWithinBoundary(user,
/*deadEndBlocks=*/nullptr)) {
llvm::errs() << "User found outside scope: " << *user;
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/SILOptimizer/Mandatory/AddressLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ static bool isStoreCopy(SILValue value) {
if (summary.innerBorrowKind != InnerBorrowKind::Contained) {
return true;
}
if (!liveness.isWithinBoundary(storeInst)) {
if (!liveness.isWithinBoundary(storeInst, /*deadEndBlocks=*/nullptr)) {
return true;
}
return false;
Expand Down
3 changes: 2 additions & 1 deletion lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,8 @@ static SILValue tryRewriteToPartialApplyStack(
if (!origUse->getUser()->mayWriteToMemory()) {
return true;
}
if (closureLiveness.isWithinBoundary(origUse->getUser())) {
if (closureLiveness.isWithinBoundary(origUse->getUser(),
/*deadEndBlocks=*/nullptr)) {
origIsUnmodifiedDuringClosureLifetime = false;
LLVM_DEBUG(llvm::dbgs() << "-- original has other possibly writing "
"use during closure lifetime\n";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,8 @@ bool ConsumeOperatorCopyableValuesChecker::check() {
mvi->setAllowsDiagnostics(false);

LLVM_DEBUG(llvm::dbgs() << "Move Value: " << *mvi);
if (livenessInfo.liveness->isWithinBoundary(mvi)) {
if (livenessInfo.liveness->isWithinBoundary(
mvi, /*deadEndBlocks=*/nullptr)) {
LLVM_DEBUG(llvm::dbgs() << " WithinBoundary: Yes!\n");
emitDiagnosticForMove(lexicalValue, varName, mvi);
} else {
Expand Down
2 changes: 1 addition & 1 deletion lib/SILOptimizer/Mandatory/DiagnoseLifetimeIssues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ static bool isOutOfLifetime(SILInstruction *inst, SSAPrunedLiveness &liveness) {
// impossible that a use of the object is not a potential load. So we would
// always see a potential load if the lifetime of the object goes beyond the
// store_weak.
return !liveness.isWithinBoundary(inst);
return !liveness.isWithinBoundary(inst, /*deadEndBlocks=*/nullptr);
}

/// Reports a warning if the stored object \p storedObj is never loaded within
Expand Down
4 changes: 2 additions & 2 deletions lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2052,8 +2052,8 @@ struct GatherUsesVisitor : public TransitiveAddressWalker<GatherUsesVisitor> {
liveness->initializeDef(bai);
liveness->computeSimple();
for (auto *consumingUse : li->getConsumingUses()) {
if (!liveness->areUsesWithinBoundary(
{consumingUse},
if (!liveness->isWithinBoundary(
consumingUse->getUser(),
moveChecker.deba->get(consumingUse->getFunction()))) {
diagnosticEmitter.emitAddressExclusivityHazardDiagnostic(
markedValue, consumingUse->getUser());
Expand Down
2 changes: 1 addition & 1 deletion lib/SILOptimizer/Mandatory/ReferenceBindingTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ struct ValidateAllUsesWithinLiveness : public AccessUseVisitor {
if (isa<EndAccessInst>(user))
return true;

if (liveness.isWithinBoundary(user)) {
if (liveness.isWithinBoundary(user, /*deadEndBlocks=*/nullptr)) {
LLVM_DEBUG(llvm::dbgs() << "User in boundary: " << *user);
diagnose(op->getUser(),
diag::sil_referencebinding_src_used_within_inout_scope);
Expand Down
4 changes: 2 additions & 2 deletions lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ void CanonicalizeOSSALifetime::extendLivenessToDeadEnds() {
SSAPrunedLiveness completeLiveness(*liveness, &discoveredBlocks);

for (auto destroy : destroys) {
if (liveness->isWithinBoundary(destroy))
if (liveness->isWithinBoundary(destroy, /*deadEndBlocks=*/nullptr))
continue;
completeLiveness.updateForUse(destroy, /*lifetimeEnding*/ true);
}
Expand Down Expand Up @@ -592,7 +592,7 @@ void CanonicalizeOSSALifetime::visitExtendedUnconsumedBoundary(

#ifndef NDEBUG
for (auto *consume : consumes) {
assert(!liveness->isWithinBoundary(consume));
assert(!liveness->isWithinBoundary(consume, /*deadEndBlocks=*/nullptr));
}
#endif

Expand Down