Skip to content

Commit febde3d

Browse files
committed
SemanticARCOpts fix - remove deadEndBlocks checks
SemanticARCOptVisitor::performGuaranteedCopyValueOptimization was converting this SIL %borrow = begin_borrow %copiedValue %copy = copy_value %borrow %borrowCopy = begin_borrow %copy end_borrow %borrow end_borrow %borrowCopy destroy_value %copy // something something unreachable into %borrow = begin_borrow %copiedValue %innerBorrow = begin_borrow %borrow end_borrow %borrow end_borrow %innerBorrow // something something unreachable Dead-end blocks are simply irrelevant for this optimization. Unfortunately, there were multiple layers of attempted workarounds that were hiding the real problem, except in rare cases. Thanks Nate Chandler for reducing the test.
1 parent d9fd6cb commit febde3d

File tree

6 files changed

+29
-18
lines changed

6 files changed

+29
-18
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,11 @@ struct BorrowedValue {
566566
/// This ignores reborrows. The assumption is that, since \p uses are
567567
/// dominated by this local scope, checking the extended borrow scope should
568568
/// not be necessary to determine they are within the scope.
569+
///
570+
/// \p deadEndBlocks is optional during transition. It will be completely
571+
/// removed in an upcoming commit.
569572
bool areUsesWithinLocalScope(ArrayRef<Operand *> uses,
570-
DeadEndBlocks &deadEndBlocks) const;
573+
DeadEndBlocks *deadEndBlocks) const;
571574

572575
/// Given a local borrow scope introducer, visit all non-forwarding consuming
573576
/// users. This means that this looks through guaranteed block arguments. \p

include/swift/SIL/PrunedLiveness.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,9 @@ class PrunedLiveness {
334334
/// client already knows that inst occurs after the start of liveness.
335335
bool isWithinBoundary(SILInstruction *inst) const;
336336

337+
/// \p deadEndBlocks is optional.
337338
bool areUsesWithinBoundary(ArrayRef<Operand *> uses,
338-
DeadEndBlocks &deadEndBlocks) const;
339+
DeadEndBlocks *deadEndBlocks) const;
339340

340341
/// Compute liveness for a single SSA definition.
341342
void computeSSALiveness(SILValue def);

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ void BorrowedValue::computeLiveness(PrunedLiveness &liveness) const {
627627
}
628628

629629
bool BorrowedValue::areUsesWithinLocalScope(
630-
ArrayRef<Operand *> uses, DeadEndBlocks &deadEndBlocks) const {
630+
ArrayRef<Operand *> uses, DeadEndBlocks *deadEndBlocks) const {
631631
// First make sure that we actually have a local scope. If we have a non-local
632632
// scope, then we have something (like a SILFunctionArgument) where a larger
633633
// semantic construct (in the case of SILFunctionArgument, the function
@@ -906,14 +906,14 @@ bool AddressOwnership::areUsesWithinLifetime(
906906
SILValue root = base.getOwnershipReferenceRoot();
907907
BorrowedValue borrow(root);
908908
if (borrow)
909-
return borrow.areUsesWithinLocalScope(uses, deadEndBlocks);
909+
return borrow.areUsesWithinLocalScope(uses, &deadEndBlocks);
910910

911911
// --- A reference no borrow scope. Currently happens for project_box.
912912

913913
// Compute the reference value's liveness.
914914
PrunedLiveness liveness;
915915
liveness.computeSSALiveness(root);
916-
return liveness.areUsesWithinBoundary(uses, deadEndBlocks);
916+
return liveness.areUsesWithinBoundary(uses, &deadEndBlocks);
917917
}
918918

919919
//===----------------------------------------------------------------------===//

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,14 @@ bool PrunedLiveness::isWithinBoundary(SILInstruction *inst) const {
154154
}
155155

156156
bool PrunedLiveness::areUsesWithinBoundary(ArrayRef<Operand *> uses,
157-
DeadEndBlocks &deadEndBlocks) const {
157+
DeadEndBlocks *deadEndBlocks) const {
158+
auto checkDeadEnd = [deadEndBlocks](SILInstruction *inst) {
159+
return deadEndBlocks && deadEndBlocks->isDeadEnd(inst->getParent());
160+
};
161+
158162
for (auto *use : uses) {
159163
auto *user = use->getUser();
160-
if (!isWithinBoundary(user) && !deadEndBlocks.isDeadEnd(user->getParent()))
164+
if (!isWithinBoundary(user) && !checkDeadEnd(user))
161165
return false;
162166
}
163167
return true;

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
153153
// dead end blocks that use the value in a non-consuming way.
154154
//
155155
// TODO: There may be some way of sinking this into the loop below.
156+
//
157+
// FIXME: The haveAnyLocalScopes and destroy.empty() checks are relics of
158+
// attempts to handle dead end blocks during areUsesWithinLocalScope. If we
159+
// don't use dead end blocks at all, they should not be relevant.
156160
bool haveAnyLocalScopes =
157161
llvm::any_of(borrowScopeIntroducers, [](BorrowedValue borrowScope) {
158162
return borrowScope.isLocalScope();
@@ -177,17 +181,16 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
177181
// anyways, we want to be conservative here and optimize only if we do not
178182
// need to insert an end_borrow since all of our borrow introducers are
179183
// non-local scopes.
184+
//
185+
// The call to areUsesWithinLocalScope cannot consider dead-end blocks. A
186+
// local borrow scope requires all its inner uses to be inside the borrow
187+
// scope, regardless of whether the end of the scope is inside a dead-end
188+
// block.
180189
{
181-
bool foundNonDeadEnd = false;
182-
for (auto *d : destroys) {
183-
foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(d->getParentBlock());
184-
}
185-
if (!foundNonDeadEnd && haveAnyLocalScopes)
186-
return false;
187190
SmallVector<Operand *, 8> scratchSpace;
188191
if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) {
189-
return !borrowScope.areUsesWithinLocalScope(lr.getAllConsumingUses(),
190-
getDeadEndBlocks());
192+
return !borrowScope.areUsesWithinLocalScope(lr.getAllConsumingUses(),
193+
nullptr);
191194
})) {
192195
return false;
193196
}
@@ -216,7 +219,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
216219

217220
if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) {
218221
return !borrowScope.areUsesWithinLocalScope(
219-
phiArgLR.getAllConsumingUses(), getDeadEndBlocks());
222+
phiArgLR.getAllConsumingUses(), nullptr);
220223
})) {
221224
return false;
222225
}

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ GuaranteedOwnershipExtension::checkBorrowExtension(
176176
assert(guaranteedLiveness.empty());
177177
borrow.computeLiveness(guaranteedLiveness);
178178

179-
if (guaranteedLiveness.areUsesWithinBoundary(newUses, deBlocks))
179+
if (guaranteedLiveness.areUsesWithinBoundary(newUses, &deBlocks))
180180
return Valid; // reuse the borrow scope as-is
181181

182182
beginBorrow = dyn_cast<BeginBorrowInst>(borrow.value);
@@ -224,7 +224,7 @@ GuaranteedOwnershipExtension::checkLifetimeExtension(
224224
ownedConsumeBlocks.push_back(user->getParent());
225225
}
226226
}
227-
if (ownedLifetime.areUsesWithinBoundary(newUses, deBlocks))
227+
if (ownedLifetime.areUsesWithinBoundary(newUses, &deBlocks))
228228
return Valid;
229229

230230
return ExtendLifetime; // Can't cover newUses without destroy sinking.

0 commit comments

Comments
 (0)