Skip to content

Commit 9036b03

Browse files
Merge pull request #68381 from nate-chandler/cherrypick/release/5.9/gh68328
5.9: [MoveChecker] Complete lifetimes before checking.
2 parents 3f85d2a + 2bad5c7 commit 9036b03

File tree

10 files changed

+330
-5
lines changed

10 files changed

+330
-5
lines changed

include/swift/SIL/OwnershipUseVisitor.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,23 @@ bool OwnershipUseVisitor<Impl>::visitInnerBorrowScopeEnd(Operand *borrowEnd) {
283283
case OperandOwnership::EndBorrow:
284284
return handleUsePoint(borrowEnd, UseLifetimeConstraint::NonLifetimeEnding);
285285

286-
case OperandOwnership::Reborrow:
286+
case OperandOwnership::Reborrow: {
287287
if (!asImpl().handleInnerReborrow(borrowEnd))
288288
return false;
289289

290290
return handleUsePoint(borrowEnd, UseLifetimeConstraint::NonLifetimeEnding);
291+
}
292+
case OperandOwnership::DestroyingConsume: {
293+
// partial_apply [on_stack] can introduce borrowing operand and can have
294+
// destroy_value consumes.
295+
auto *pai = dyn_cast<PartialApplyInst>(borrowEnd->get());
296+
// TODO: When we have ForwardingInstruction abstraction, walk the use-def
297+
// chain to ensure we have a partial_apply [on_stack] def.
298+
assert(pai && pai->isOnStack() ||
299+
OwnershipForwardingMixin::get(
300+
cast<SingleValueInstruction>(borrowEnd->get())));
301+
return handleUsePoint(borrowEnd, UseLifetimeConstraint::NonLifetimeEnding);
302+
}
291303

292304
default:
293305
llvm_unreachable("expected borrow scope end");
@@ -388,8 +400,9 @@ bool OwnershipUseVisitor<Impl>::visitGuaranteedUse(Operand *use) {
388400
case OperandOwnership::ForwardingUnowned:
389401
case OperandOwnership::UnownedInstantaneousUse:
390402
case OperandOwnership::BitwiseEscape:
391-
case OperandOwnership::EndBorrow:
392403
return handleUsePoint(use, UseLifetimeConstraint::NonLifetimeEnding);
404+
case OperandOwnership::EndBorrow:
405+
return handleUsePoint(use, UseLifetimeConstraint::LifetimeEnding);
393406

394407
case OperandOwnership::Reborrow:
395408
if (!asImpl().handleOuterReborrow(use))

include/swift/SIL/OwnershipUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,9 @@ struct BorrowingOperand {
477477
/// valid BorrowedValue instance.
478478
BorrowedValue getBorrowIntroducingUserResult();
479479

480+
/// Return the borrowing operand's value.
481+
SILValue getScopeIntroducingUserResult();
482+
480483
/// Compute the implicit uses that this borrowing operand "injects" into the
481484
/// set of its operands uses.
482485
///

include/swift/SIL/SILInstruction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,11 @@ class OwnershipForwardingMixin {
12611261
///
12621262
/// \p inst is an OwnershipForwardingMixin
12631263
static bool isAddressOnly(SILInstruction *inst);
1264+
1265+
// Call \p visitor on all forwarded results of the current forwarding
1266+
// operation.
1267+
static bool visitForwardedValues(SILInstruction *inst,
1268+
function_ref<bool(SILValue)> visitor);
12641269
};
12651270

12661271
/// A single value inst that forwards a static ownership from its first operand.

lib/SIL/IR/SILInstructions.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3276,6 +3276,31 @@ bool OwnershipForwardingMixin::isAddressOnly(SILInstruction *inst) {
32763276
return inst->getOperand(0)->getType().isAddressOnly(*inst->getFunction());
32773277
}
32783278

3279+
bool OwnershipForwardingMixin::visitForwardedValues(
3280+
SILInstruction *inst, function_ref<bool(SILValue)> visitor) {
3281+
if (auto *svi = dyn_cast<SingleValueInstruction>(inst)) {
3282+
return visitor(svi);
3283+
}
3284+
if (auto *mvri = dyn_cast<MultipleValueInstruction>(inst)) {
3285+
return llvm::all_of(mvri->getResults(), [&](SILValue value) {
3286+
if (value->getOwnershipKind() == OwnershipKind::None)
3287+
return true;
3288+
return visitor(value);
3289+
});
3290+
}
3291+
auto *ti = cast<TermInst>(inst);
3292+
assert(ti->mayHaveTerminatorResult());
3293+
return llvm::all_of(ti->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) {
3294+
// If we do not have any arguments, then continue.
3295+
if (succBlock->args_empty())
3296+
return true;
3297+
3298+
auto args = succBlock->getSILPhiArguments();
3299+
assert(args.size() == 1 && "Transforming terminator with multiple args?!");
3300+
return visitor(args[0]);
3301+
});
3302+
}
3303+
32793304
// This may be called in an invalid SIL state. SILCombine creates new
32803305
// terminators in non-terminator position and defers deleting the original
32813306
// terminator until after all modification.

lib/SIL/Utils/OSSALifetimeCompletion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ static bool endLifetimeAtUnreachableBlocks(SILValue value,
129129
changed = true;
130130
}
131131
for (auto *successor : block->getSuccessorBlocks()) {
132-
deadEndBlocks.push(successor);
132+
deadEndBlocks.pushIfNotVisited(successor);
133133
}
134134
}
135135
return changed;

lib/SIL/Utils/OwnershipLiveness.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,10 @@ struct InteriorLivenessVisitor :
140140
/// Handles begin_borrow, load_borrow, store_borrow, begin_apply.
141141
bool handleInnerBorrow(BorrowingOperand borrowingOperand) {
142142
if (handleInnerScopeCallback) {
143-
handleInnerScopeCallback(
144-
borrowingOperand.getBorrowIntroducingUserResult().value);
143+
auto value = borrowingOperand.getScopeIntroducingUserResult();
144+
if (value) {
145+
handleInnerScopeCallback(value);
146+
}
145147
}
146148
return true;
147149
}

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,30 @@ BorrowedValue BorrowingOperand::getBorrowIntroducingUserResult() {
751751
llvm_unreachable("covered switch");
752752
}
753753

754+
SILValue BorrowingOperand::getScopeIntroducingUserResult() {
755+
switch (kind) {
756+
case BorrowingOperandKind::Invalid:
757+
case BorrowingOperandKind::Yield:
758+
case BorrowingOperandKind::Apply:
759+
case BorrowingOperandKind::TryApply:
760+
return SILValue();
761+
762+
case BorrowingOperandKind::BeginAsyncLet:
763+
case BorrowingOperandKind::PartialApplyStack:
764+
case BorrowingOperandKind::BeginBorrow:
765+
return cast<SingleValueInstruction>(op->getUser());
766+
767+
case BorrowingOperandKind::BeginApply:
768+
return cast<BeginApplyInst>(op->getUser())->getTokenResult();
769+
770+
case BorrowingOperandKind::Branch: {
771+
PhiOperand phiOp(op);
772+
return phiOp.getValue();
773+
}
774+
}
775+
llvm_unreachable("covered switch");
776+
}
777+
754778
void BorrowingOperand::getImplicitUses(
755779
SmallVectorImpl<Operand *> &foundUses) const {
756780
// FIXME: this visitScopeEndingUses should never return false once dead

lib/SILOptimizer/Mandatory/MoveOnlyChecker.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/SIL/FieldSensitivePrunedLiveness.h"
3131
#include "swift/SIL/InstructionUtils.h"
3232
#include "swift/SIL/MemAccessUtils.h"
33+
#include "swift/SIL/OSSALifetimeCompletion.h"
3334
#include "swift/SIL/OwnershipUtils.h"
3435
#include "swift/SIL/PrunedLiveness.h"
3536
#include "swift/SIL/SILArgument.h"
@@ -86,6 +87,7 @@ struct MoveOnlyChecker {
8687
}
8788

8889
void checkObjects();
90+
void completeObjectLifetimes(ArrayRef<MarkMustCheckInst *>);
8991
void checkAddresses();
9092
};
9193

@@ -109,10 +111,75 @@ void MoveOnlyChecker::checkObjects() {
109111
return;
110112
}
111113

114+
completeObjectLifetimes(moveIntroducersToProcess.getArrayRef());
115+
112116
MoveOnlyObjectChecker checker{diagnosticEmitter, domTree, poa, allocator};
113117
madeChange |= checker.check(moveIntroducersToProcess);
114118
}
115119

120+
void MoveOnlyChecker::completeObjectLifetimes(
121+
ArrayRef<MarkMustCheckInst *> insts) {
122+
// TODO: Delete once OSSALifetimeCompletion is run as part of SILGenCleanup.
123+
OSSALifetimeCompletion completion(fn, domTree);
124+
125+
// Collect all values derived from each mark_unresolved_non_copyable_value
126+
// instruction via ownership instructions and phis.
127+
ValueWorklist transitiveValues(fn);
128+
for (auto *inst : insts) {
129+
transitiveValues.push(inst);
130+
}
131+
while (auto value = transitiveValues.pop()) {
132+
for (auto *use : value->getUses()) {
133+
auto *user = use->getUser();
134+
switch (user->getKind()) {
135+
case SILInstructionKind::BeginBorrowInst:
136+
case SILInstructionKind::CopyValueInst:
137+
case SILInstructionKind::MoveValueInst:
138+
transitiveValues.pushIfNotVisited(cast<SingleValueInstruction>(user));
139+
break;
140+
case SILInstructionKind::BranchInst: {
141+
PhiOperand po(use);
142+
transitiveValues.pushIfNotVisited(po.getValue());
143+
break;
144+
}
145+
default: {
146+
auto *forward = OwnershipForwardingMixin::get(user);
147+
if (!forward)
148+
continue;
149+
OwnershipForwardingMixin::visitForwardedValues(
150+
user, [&transitiveValues](auto forwarded) {
151+
transitiveValues.pushIfNotVisited(forwarded);
152+
return true;
153+
});
154+
break;
155+
}
156+
}
157+
}
158+
}
159+
// Complete the lifetime of each collected value. This is a subset of the
160+
// work that SILGenCleanup will do.
161+
for (auto *block : poa->get(fn)->getPostOrder()) {
162+
for (SILInstruction &inst : reverse(*block)) {
163+
for (auto result : inst.getResults()) {
164+
if (!transitiveValues.isVisited(result))
165+
continue;
166+
if (completion.completeOSSALifetime(result) ==
167+
LifetimeCompletion::WasCompleted) {
168+
madeChange = true;
169+
}
170+
}
171+
}
172+
for (SILArgument *arg : block->getArguments()) {
173+
if (!transitiveValues.isVisited(arg))
174+
continue;
175+
if (completion.completeOSSALifetime(arg) ==
176+
LifetimeCompletion::WasCompleted) {
177+
madeChange = true;
178+
}
179+
}
180+
}
181+
}
182+
116183
void MoveOnlyChecker::checkAddresses() {
117184
unsigned diagCount = diagnosticEmitter.getDiagnosticCount();
118185
SmallSetVector<MarkMustCheckInst *, 32> moveIntroducersToProcess;

0 commit comments

Comments
 (0)