Skip to content

Commit dceca2b

Browse files
committed
[ownership] Create a context structure for the linear lifetime checker.
This is just a simple refactoring commit in preparation for hiding more of the details of the linear lifetime checker. This is NFC, just moving around code.
1 parent 4eb3163 commit dceca2b

File tree

7 files changed

+67
-47
lines changed

7 files changed

+67
-47
lines changed

include/swift/SIL/OwnershipUtils.h

+42-19
Original file line numberDiff line numberDiff line change
@@ -127,27 +127,50 @@ class LinearLifetimeError {
127127
}
128128
};
129129

130-
/// Returns true if:
130+
/// A class used to validate linear lifetime with respect to an SSA-like
131+
/// definition.
131132
///
132-
/// 1. No consuming uses are reachable from any other consuming use, from any
133-
/// non-consuming uses, or from the producer instruction.
134-
/// 2. The consuming use set jointly post dominates producers and all non
135-
/// consuming uses.
133+
/// This class is able to both validate that a linear lifetime has been properly
134+
/// constructed (for verification and safety purposes) as well as return to the
135+
/// caller upon failure, what the failure was. In certain cases (for instance if
136+
/// there exists a path without a non-consuming use), the class will report back
137+
/// the specific insertion points needed to insert these compensating releases.
136138
///
137-
/// \p value The value whose lifetime we are checking.
138-
/// \p consumingUses the array of users that destroy or consume a value.
139-
/// \p nonConsumingUses regular uses
140-
/// \p deadEndBlocks a cache for the dead end block computation
141-
/// \p errorBehavior If we detect an error, should we return false or hard
142-
/// error.
143-
/// \p leakingBlocks If non-null a list of blocks where the value was detected
144-
/// to leak. Can be used to insert missing destroys.
145-
LinearLifetimeError valueHasLinearLifetime(
146-
SILValue value, ArrayRef<BranchPropagatedUser> consumingUses,
147-
ArrayRef<BranchPropagatedUser> nonConsumingUses,
148-
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
149-
DeadEndBlocks &deadEndBlocks, ownership::ErrorBehaviorKind errorBehavior,
150-
SmallVectorImpl<SILBasicBlock *> *leakingBlocks = nullptr);
139+
/// DISCUSSION: A linear lifetime consists of a starting block or instruction
140+
/// and a list of non-consuming uses and a set of consuming uses. The consuming
141+
/// uses must not be reachable from each other and jointly post-dominate all
142+
/// consuming uses as well as the defining block/instruction.
143+
class LinearLifetimeChecker {
144+
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
145+
DeadEndBlocks &deadEndBlocks;
146+
147+
public:
148+
LinearLifetimeChecker(SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
149+
DeadEndBlocks &deadEndBlocks)
150+
: visitedBlocks(visitedBlocks), deadEndBlocks(deadEndBlocks) {}
151+
152+
/// Returns true if:
153+
///
154+
/// 1. No consuming uses are reachable from any other consuming use, from any
155+
/// non-consuming uses, or from the producer instruction.
156+
/// 2. The consuming use set jointly post dominates producers and all non
157+
/// consuming uses.
158+
///
159+
/// Returns false otherwise.
160+
///
161+
/// \p value The value whose lifetime we are checking.
162+
/// \p consumingUses the array of users that destroy or consume a value.
163+
/// \p nonConsumingUses regular uses
164+
/// \p errorBehavior If we detect an error, should we return false or hard
165+
/// error.
166+
/// \p leakingBlocks If non-null a list of blocks where the value was detected
167+
/// to leak. Can be used to insert missing destroys.
168+
LinearLifetimeError
169+
checkValue(SILValue value, ArrayRef<BranchPropagatedUser> consumingUses,
170+
ArrayRef<BranchPropagatedUser> nonConsumingUses,
171+
ownership::ErrorBehaviorKind errorBehavior,
172+
SmallVectorImpl<SILBasicBlock *> *leakingBlocks = nullptr);
173+
};
151174

152175
/// Returns true if v is an address or trivial.
153176
bool isValueAddressOrTrivial(SILValue v);

lib/SIL/LinearLifetimeChecker.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -507,10 +507,9 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
507507
// Top Level Entrypoints
508508
//===----------------------------------------------------------------------===//
509509

510-
LinearLifetimeError swift::valueHasLinearLifetime(
510+
LinearLifetimeError LinearLifetimeChecker::checkValue(
511511
SILValue value, ArrayRef<BranchPropagatedUser> consumingUses,
512512
ArrayRef<BranchPropagatedUser> nonConsumingUses,
513-
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks, DeadEndBlocks &deBlocks,
514513
ErrorBehaviorKind errorBehavior,
515514
SmallVectorImpl<SILBasicBlock *> *leakingBlocks) {
516515
assert(!consumingUses.empty() && "Must have at least one consuming user?!");
@@ -547,7 +546,7 @@ LinearLifetimeError swift::valueHasLinearLifetime(
547546
// same block, we would have flagged.
548547
if (llvm::any_of(nonConsumingUses, [&](BranchPropagatedUser user) {
549548
return user.getParent() != value->getParentBlock() &&
550-
!deBlocks.isDeadEnd(user.getParent());
549+
!deadEndBlocks.isDeadEnd(user.getParent());
551550
})) {
552551
state.error.handleUseAfterFree([&] {
553552
llvm::errs() << "Function: '" << value->getFunction()->getName()
@@ -592,10 +591,10 @@ LinearLifetimeError swift::valueHasLinearLifetime(
592591

593592
// Now that our algorithm is completely prepared, run the
594593
// dataflow... If we find a failure, return false.
595-
state.performDataflow(deBlocks);
594+
state.performDataflow(deadEndBlocks);
596595

597596
// ...and then check that the end state shows that we have a valid linear
598597
// typed value.
599-
state.checkDataflowEndState(deBlocks);
598+
state.checkDataflowEndState(deadEndBlocks);
600599
return state.error;
601600
}

lib/SIL/OwnershipUtils.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ bool BorrowScopeIntroducingValue::areInstructionsWithinScope(
206206
visitLocalScopeEndingInstructions(
207207
[&scratchSpace](SILInstruction *i) { scratchSpace.emplace_back(i); });
208208

209-
auto result = valueHasLinearLifetime(
210-
value, scratchSpace, instructions, visitedBlocks, deadEndBlocks,
211-
ownership::ErrorBehaviorKind::ReturnFalse);
209+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
210+
auto result = checker.checkValue(value, scratchSpace, instructions,
211+
ownership::ErrorBehaviorKind::ReturnFalse);
212212
return !result.getFoundError();
213213
}

lib/SIL/SILOwnershipVerifier.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ class SILValueOwnershipChecker {
136136
SmallVector<BranchPropagatedUser, 32> allRegularUsers;
137137
llvm::copy(regularUsers, std::back_inserter(allRegularUsers));
138138
llvm::copy(implicitRegularUsers, std::back_inserter(allRegularUsers));
139-
auto linearLifetimeResult =
140-
valueHasLinearLifetime(value, lifetimeEndingUsers, allRegularUsers,
141-
visitedBlocks, deadEndBlocks, errorBehavior);
139+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
140+
auto linearLifetimeResult = checker.checkValue(
141+
value, lifetimeEndingUsers, allRegularUsers, errorBehavior);
142142
result = !linearLifetimeResult.getFoundError();
143143

144144
return result.getValue();

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ static void fixupReferenceCounts(
150150
// just cares about the block the value is in. In a forthcoming commit, I
151151
// am going to change this to use a different API on the linear lifetime
152152
// checker that makes this clearer.
153-
auto error =
154-
valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks,
155-
deadEndBlocks, errorBehavior, &leakingBlocks);
153+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
154+
auto error = checker.checkValue(pai, {applySite}, {}, errorBehavior,
155+
&leakingBlocks);
156156
if (error.getFoundLeak()) {
157157
while (!leakingBlocks.empty()) {
158158
auto *leakingBlock = leakingBlocks.pop_back_val();
@@ -201,9 +201,9 @@ static void fixupReferenceCounts(
201201
// just cares about the block the value is in. In a forthcoming commit, I
202202
// am going to change this to use a different API on the linear lifetime
203203
// checker that makes this clearer.
204-
auto error =
205-
valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks,
206-
deadEndBlocks, errorBehavior, &leakingBlocks);
204+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
205+
auto error = checker.checkValue(pai, {applySite}, {}, errorBehavior,
206+
&leakingBlocks);
207207
if (error.getFoundError()) {
208208
while (!leakingBlocks.empty()) {
209209
auto *leakingBlock = leakingBlocks.pop_back_val();
@@ -240,9 +240,9 @@ static void fixupReferenceCounts(
240240
// just cares about the block the value is in. In a forthcoming commit, I
241241
// am going to change this to use a different API on the linear lifetime
242242
// checker that makes this clearer.
243-
auto error =
244-
valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks,
245-
deadEndBlocks, errorBehavior, &leakingBlocks);
243+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
244+
auto error = checker.checkValue(pai, {applySite}, {}, errorBehavior,
245+
&leakingBlocks);
246246
if (error.getFoundError()) {
247247
while (!leakingBlocks.empty()) {
248248
auto *leakingBlock = leakingBlocks.pop_back_val();

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -780,9 +780,8 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues(
780780
// Then perform the linear lifetime check. If we succeed, continue. We have
781781
// no further work to do.
782782
auto errorKind = ownership::ErrorBehaviorKind::ReturnFalse;
783-
auto error =
784-
valueHasLinearLifetime(cvi, {svi}, {}, visitedBlocks, deadEndBlocks,
785-
errorKind, &leakingBlocks);
783+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
784+
auto error = checker.checkValue(cvi, {svi}, {}, errorKind, &leakingBlocks);
786785
if (!error.getFoundError())
787786
continue;
788787

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -671,11 +671,10 @@ class StorageGuaranteesLoadVisitor
671671
}
672672

673673
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
674-
675-
auto result = valueHasLinearLifetime(baseObject, baseEndBorrows,
676-
valueDestroys, visitedBlocks,
677-
ARCOpt.getDeadEndBlocks(),
678-
ownership::ErrorBehaviorKind::ReturnFalse);
674+
675+
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
676+
auto result = checker.checkValue(baseObject, baseEndBorrows, valueDestroys,
677+
ownership::ErrorBehaviorKind::ReturnFalse);
679678
return answer(result.getFoundError());
680679
}
681680

0 commit comments

Comments
 (0)