Skip to content

Commit 1dfd8d6

Browse files
authored
Merge pull request swiftlang#66094 from gottesmm/pr-9cc91f1b6b3ff60686adb825c4a444221c3d798a
[move-only] Teach SILGenApply how to emit subscripts with borrowed base values.
2 parents 9984247 + 2b785e4 commit 1dfd8d6

10 files changed

+3130
-29
lines changed

lib/SILGen/ArgumentSource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ class ArgumentSource {
280280

281281
ArgumentSource copyForDiagnostics() const;
282282

283-
void dump() const;
283+
LLVM_DUMP_METHOD void dump() const;
284284
void dump(raw_ostream &os, unsigned indent = 0) const;
285285

286286
private:

lib/SILGen/SILGenApply.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3029,7 +3029,8 @@ static StorageRefResult findStorageReferenceExprForBorrow(Expr *e) {
30293029
return result.withTransitiveRoot(te);
30303030

30313031
} else if (auto ioe = dyn_cast<InOutExpr>(e)) {
3032-
return ioe;
3032+
if (auto result = findStorageReferenceExprForBorrow(ioe->getSubExpr()))
3033+
return result.withTransitiveRoot(ioe);
30333034
}
30343035

30353036
return StorageRefResult();
@@ -3049,6 +3050,24 @@ Expr *ArgumentSource::findStorageReferenceExprForMoveOnly(
30493050
sawLoad = true;
30503051
}
30513052

3053+
// If we have a subscript, strip it off and make sure that our base is
3054+
// something that we can process. If we do and we succeed below, we return the
3055+
// subscript instead.
3056+
SubscriptExpr *subscriptExpr = nullptr;
3057+
if ((subscriptExpr = dyn_cast<SubscriptExpr>(argExpr))) {
3058+
auto *decl = cast<SubscriptDecl>(subscriptExpr->getDecl().getDecl());
3059+
if (decl->getReadImpl() != ReadImplKind::Read) {
3060+
subscriptExpr = nullptr;
3061+
} else {
3062+
argExpr = subscriptExpr->getBase();
3063+
}
3064+
3065+
// If there's a load on the base of the subscript expr, look past it.
3066+
if (auto *li = dyn_cast<LoadExpr>(argExpr)) {
3067+
argExpr = li->getSubExpr();
3068+
}
3069+
}
3070+
30523071
// If we're consuming instead, then the load _must_ have been there.
30533072
if (kind == StorageReferenceOperationKind::Consume && !sawLoad)
30543073
return nullptr;
@@ -3097,6 +3116,12 @@ Expr *ArgumentSource::findStorageReferenceExprForMoveOnly(
30973116
// has a move only base.
30983117
(void)std::move(*this).asKnownExpr();
30993118

3119+
// If we saw a subscript expr and the base of the subscript expr passed our
3120+
// tests above, we can emit the call to the subscript directly as a borrowed
3121+
// lvalue. Return the subscript expr here so that we emit it appropriately.
3122+
if (subscriptExpr)
3123+
return subscriptExpr;
3124+
31003125
return result.getTransitiveRoot();
31013126
}
31023127

lib/SILGen/SILGenDecl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,13 +1964,19 @@ InitializationPtr SILGenFunction::emitLocalVariableWithCleanup(
19641964
std::unique_ptr<TemporaryInitialization>
19651965
SILGenFunction::emitTemporary(SILLocation loc, const TypeLowering &tempTL) {
19661966
SILValue addr = emitTemporaryAllocation(loc, tempTL.getLoweredType());
1967+
if (addr->getType().isMoveOnly())
1968+
addr = B.createMarkMustCheckInst(
1969+
loc, addr, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
19671970
return useBufferAsTemporary(addr, tempTL);
19681971
}
19691972

19701973
std::unique_ptr<TemporaryInitialization>
19711974
SILGenFunction::emitFormalAccessTemporary(SILLocation loc,
19721975
const TypeLowering &tempTL) {
19731976
SILValue addr = emitTemporaryAllocation(loc, tempTL.getLoweredType());
1977+
if (addr->getType().isMoveOnly())
1978+
addr = B.createMarkMustCheckInst(
1979+
loc, addr, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
19741980
CleanupHandle cleanup =
19751981
enterDormantFormalAccessTemporaryCleanup(addr, loc, tempTL);
19761982
return std::unique_ptr<TemporaryInitialization>(

lib/SILGen/SILGenLValue.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ LogicalPathComponent::projectForRead(SILGenFunction &SGF, SILLocation loc,
366366
}
367367

368368
TemporaryInitializationPtr tempInit;
369+
ManagedValue result;
369370
RValue rvalue;
370371

371372
// If the RValue type has an openedExistential, then the RValue must be
@@ -377,9 +378,11 @@ LogicalPathComponent::projectForRead(SILGenFunction &SGF, SILLocation loc,
377378

378379
// Create a temporary, whose type may depend on the 'get'.
379380
tempInit = SGF.emitFormalAccessTemporary(loc, RValueTL);
381+
result = tempInit->getManagedAddress();
380382
} else {
381383
// Create a temporary for a static (non-dependent) RValue type.
382384
tempInit = SGF.emitFormalAccessTemporary(loc, RValueTL);
385+
result = tempInit->getManagedAddress();
383386

384387
// Emit a 'get' directly into the temporary.
385388
rvalue = std::move(*this).get(SGF, loc, base, SGFContext(tempInit.get()));
@@ -390,7 +393,8 @@ LogicalPathComponent::projectForRead(SILGenFunction &SGF, SILLocation loc,
390393
if (!rvalue.isInContext())
391394
std::move(rvalue).forwardInto(SGF, loc, tempInit.get());
392395

393-
return tempInit->getManagedAddress();
396+
assert(result);
397+
return result;
394398
}
395399

396400
ManagedValue LogicalPathComponent::project(SILGenFunction &SGF,

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,29 +2523,27 @@ void MoveOnlyAddressCheckerPImpl::rewriteUses(
25232523
// scope, we would have emitted the scope expansion error during diagnostics.
25242524
for (auto pair : addressUseState.borrows) {
25252525
if (auto *li = dyn_cast<LoadInst>(pair.first)) {
2526-
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Copy) {
2527-
// If we had a load [copy], borrow then we know that all of its destroys
2528-
// must have been destroy_value. So we can just gather up those
2529-
// destroy_value and use then to create a new load_borrow scope.
2530-
SILBuilderWithScope builder(li);
2531-
auto *lbi = builder.createLoadBorrow(li->getLoc(), li->getOperand());
2532-
// We use this auxillary list to avoid iterator invalidation of
2533-
// li->getConsumingUse();
2534-
StackList<DestroyValueInst *> toDelete(lbi->getFunction());
2535-
for (auto *consumeUse : li->getConsumingUses()) {
2536-
auto *dvi = cast<DestroyValueInst>(consumeUse->getUser());
2537-
SILBuilderWithScope destroyBuilder(dvi);
2538-
destroyBuilder.createEndBorrow(dvi->getLoc(), lbi);
2539-
toDelete.push_back(dvi);
2540-
changed = true;
2541-
}
2542-
while (!toDelete.empty())
2543-
toDelete.pop_back_val()->eraseFromParent();
2544-
2545-
li->replaceAllUsesWith(lbi);
2546-
li->eraseFromParent();
2547-
continue;
2526+
// If we had a load -> load_borrow then we know that all of its destroys
2527+
// must have been destroy_value. So we can just gather up those
2528+
// destroy_value and use then to create a new load_borrow scope.
2529+
SILBuilderWithScope builder(li);
2530+
auto *lbi = builder.createLoadBorrow(li->getLoc(), li->getOperand());
2531+
// We use this auxillary list to avoid iterator invalidation of
2532+
// li->getConsumingUse();
2533+
StackList<DestroyValueInst *> toDelete(lbi->getFunction());
2534+
for (auto *consumeUse : li->getConsumingUses()) {
2535+
auto *dvi = cast<DestroyValueInst>(consumeUse->getUser());
2536+
SILBuilderWithScope destroyBuilder(dvi);
2537+
destroyBuilder.createEndBorrow(dvi->getLoc(), lbi);
2538+
toDelete.push_back(dvi);
2539+
changed = true;
25482540
}
2541+
while (!toDelete.empty())
2542+
toDelete.pop_back_val()->eraseFromParent();
2543+
2544+
li->replaceAllUsesWith(lbi);
2545+
li->eraseFromParent();
2546+
continue;
25492547
}
25502548

25512549
llvm::dbgs() << "Borrow: " << *pair.first;

0 commit comments

Comments
 (0)