Skip to content

Commit d75a62c

Browse files
committed
SIL: Enclose switch subjects in a new begin_borrow [fixed] variant.
We want to preserve the borrow scope during switch dispatch so that move-only checking doesn't try to analyze destructures or consumes out of it. SILGen should mark anywhere that's a potential possibility with its own marker so that it gets borrow checked independently.
1 parent eca40f3 commit d75a62c

File tree

14 files changed

+100
-35
lines changed

14 files changed

+100
-35
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -818,12 +818,13 @@ class SILBuilder {
818818
BeginBorrowInst *createBeginBorrow(SILLocation Loc, SILValue LV,
819819
bool isLexical = false,
820820
bool hasPointerEscape = false,
821-
bool fromVarDecl = false) {
821+
bool fromVarDecl = false,
822+
bool fixed = false) {
822823
assert(getFunction().hasOwnership());
823824
assert(!LV->getType().isAddress());
824825
return insert(new (getModule())
825826
BeginBorrowInst(getSILDebugLocation(Loc), LV, isLexical,
826-
hasPointerEscape, fromVarDecl));
827+
hasPointerEscape, fromVarDecl, fixed));
827828
}
828829

829830
/// Convenience function for creating a load_borrow on non-trivial values and

include/swift/SIL/SILInstruction.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4524,15 +4524,18 @@ class BeginBorrowInst
45244524
USE_SHARED_UINT8;
45254525

45264526
BeginBorrowInst(SILDebugLocation DebugLoc, SILValue LValue, bool isLexical,
4527-
bool hasPointerEscape, bool fromVarDecl)
4527+
bool hasPointerEscape, bool fromVarDecl, bool fixed)
45284528
: UnaryInstructionBase(DebugLoc, LValue,
45294529
LValue->getType().getObjectType()) {
45304530
sharedUInt8().BeginBorrowInst.lexical = isLexical;
45314531
sharedUInt8().BeginBorrowInst.pointerEscape = hasPointerEscape;
45324532
sharedUInt8().BeginBorrowInst.fromVarDecl = fromVarDecl;
4533+
sharedUInt8().BeginBorrowInst.fixed = fixed;
45334534
}
45344535

45354536
public:
4537+
4538+
45364539
// FIXME: this does not return all instructions that end a local borrow
45374540
// scope. Branches can also end it via a reborrow, so APIs using this are
45384541
// incorrect. Instead, either iterate over all uses and return those with
@@ -4560,6 +4563,12 @@ class BeginBorrowInst
45604563
return sharedUInt8().BeginBorrowInst.fromVarDecl;
45614564
}
45624565

4566+
/// Whether the borrow scope is fixed during move checking and should be
4567+
/// treated as an opaque use of the value.
4568+
bool isFixed() const {
4569+
return sharedUInt8().BeginBorrowInst.fixed;
4570+
}
4571+
45634572
/// Return a range over all EndBorrow instructions for this BeginBorrow.
45644573
EndBorrowRange getEndBorrows() const;
45654574

include/swift/SIL/SILNode.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ class alignas(8) SILNode :
243243
SHARED_FIELD(BeginBorrowInst, uint8_t
244244
lexical : 1,
245245
pointerEscape : 1,
246-
fromVarDecl : 1);
246+
fromVarDecl : 1,
247+
fixed : 1);
247248

248249
SHARED_FIELD(CopyAddrInst, uint8_t
249250
isTakeOfSrc : 1,

lib/SIL/IR/SILPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,9 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
17371737
if (BBI->isFromVarDecl()) {
17381738
*this << "[var_decl] ";
17391739
}
1740+
if (BBI->isFixed()) {
1741+
*this << "[fixed] ";
1742+
}
17401743
*this << getIDAndType(BBI->getOperand());
17411744
}
17421745

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3711,6 +3711,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37113711
bool isLexical = false;
37123712
bool hasPointerEscape = false;
37133713
bool fromVarDecl = false;
3714+
bool fixed = false;
37143715

37153716
StringRef AttrName;
37163717
SourceLoc AttrLoc;
@@ -3721,6 +3722,8 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37213722
hasPointerEscape = true;
37223723
else if (AttrName == "var_decl")
37233724
fromVarDecl = true;
3725+
else if (AttrName == "fixed")
3726+
fixed = true;
37243727
else {
37253728
P.diagnose(InstLoc.getSourceLoc(),
37263729
diag::sil_invalid_attribute_for_instruction, AttrName,
@@ -3734,7 +3737,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
37343737
return true;
37353738

37363739
ResultVal = B.createBeginBorrow(InstLoc, Val, isLexical, hasPointerEscape,
3737-
fromVarDecl);
3740+
fromVarDecl, fixed);
37383741
break;
37393742
}
37403743

lib/SILGen/SILGenBuilder.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,13 +1038,26 @@ ManagedValue SILGenBuilder::createMarkDependence(
10381038

10391039
ManagedValue SILGenBuilder::createBeginBorrow(SILLocation loc,
10401040
ManagedValue value,
1041-
bool isLexical) {
1041+
bool isLexical,
1042+
bool isFixed) {
10421043
auto *newValue =
1043-
SILBuilder::createBeginBorrow(loc, value.getValue(), isLexical);
1044+
SILBuilder::createBeginBorrow(loc, value.getValue(),
1045+
isLexical, false, false, isFixed);
10441046
SGF.emitManagedBorrowedRValueWithCleanup(newValue);
10451047
return ManagedValue::forBorrowedObjectRValue(newValue);
10461048
}
10471049

1050+
ManagedValue SILGenBuilder::createFormalAccessBeginBorrow(SILLocation loc,
1051+
ManagedValue value,
1052+
bool isLexical,
1053+
bool isFixed) {
1054+
auto *newValue =
1055+
SILBuilder::createBeginBorrow(loc, value.getValue(),
1056+
isLexical, false, false, isFixed);
1057+
return SGF.emitFormalEvaluationManagedBorrowedRValueWithCleanup(loc,
1058+
value.getValue(), newValue);
1059+
}
1060+
10481061
ManagedValue SILGenBuilder::createMoveValue(SILLocation loc, ManagedValue value,
10491062
bool isLexical) {
10501063
assert(value.isPlusOne(SGF) && "Must be +1 to be moved!");

lib/SILGen/SILGenBuilder.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,13 @@ class SILGenBuilder : public SILBuilder {
470470

471471
using SILBuilder::createBeginBorrow;
472472
ManagedValue createBeginBorrow(SILLocation loc, ManagedValue value,
473-
bool isLexical = false);
473+
bool isLexical = false,
474+
bool isFixed = false);
475+
476+
ManagedValue createFormalAccessBeginBorrow(SILLocation loc,
477+
ManagedValue value,
478+
bool isLexical = false,
479+
bool isFixed = false);
474480

475481
using SILBuilder::createMoveValue;
476482
ManagedValue createMoveValue(SILLocation loc, ManagedValue value,

lib/SILGen/SILGenPattern.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,26 +3425,29 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
34253425

34263426
case ValueOwnership::Shared:
34273427
emission.setNoncopyableBorrowingOwnership();
3428-
if (!subjectMV.isPlusZero()) {
3429-
subjectMV = subjectMV.borrow(*this, S);
3430-
}
34313428
if (subjectMV.getType().isAddress()) {
3429+
// Initiate a read access on the memory, to ensure that even
3430+
// if the underlying memory is mutable or consumable, the pattern
3431+
// match is not allowed to modify it.
3432+
auto access = B.createBeginAccess(S, subjectMV.getValue(),
3433+
SILAccessKind::Read,
3434+
SILAccessEnforcement::Static,
3435+
/*no nested conflict*/ true, false);
3436+
Cleanups.pushCleanup<EndAccessCleanup>(access);
3437+
subjectMV = ManagedValue::forBorrowedAddressRValue(access);
34323438
if (subjectMV.getType().isLoadable(F)) {
34333439
// Load a borrow if the type is loadable.
34343440
subjectMV = subjectUndergoesFormalAccess
34353441
? B.createFormalAccessLoadBorrow(S, subjectMV)
34363442
: B.createLoadBorrow(S, subjectMV);
3437-
} else {
3438-
// Initiate a read access on the memory, to ensure that even
3439-
// if the underlying memory is mutable or consumable, the pattern
3440-
// match is not allowed to modify it.
3441-
auto access = B.createBeginAccess(S, subjectMV.getValue(),
3442-
SILAccessKind::Read,
3443-
SILAccessEnforcement::Static,
3444-
/*no nested conflict*/ true, false);
3445-
Cleanups.pushCleanup<EndAccessCleanup>(access);
3446-
subjectMV = ManagedValue::forBorrowedAddressRValue(access);
34473443
}
3444+
} else {
3445+
// Initiate a fixed borrow on the subject, so that it's treated as
3446+
// opaque by the move checker.
3447+
subjectMV = subjectUndergoesFormalAccess
3448+
? B.createFormalAccessBeginBorrow(S, subjectMV,
3449+
false, /*fixed*/true)
3450+
: B.createBeginBorrow(S, subjectMV, false, /*fixed*/ true);
34483451
}
34493452
return {subjectMV, CastConsumptionKind::BorrowAlways};
34503453

@@ -3467,8 +3470,19 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
34673470
Cleanups.getCleanupsDepth(),
34683471
subjectMV);
34693472

3470-
// Perform the pattern match on a borrow of the subject.
3471-
subjectMV = subjectMV.borrow(*this, S);
3473+
// Perform the pattern match on an opaque borrow or read access of the
3474+
// subject.
3475+
if (subjectMV.getType().isAddress()) {
3476+
auto access = B.createBeginAccess(S, subjectMV.getValue(),
3477+
SILAccessKind::Read,
3478+
SILAccessEnforcement::Static,
3479+
/*no nested conflict*/ true, false);
3480+
Cleanups.pushCleanup<EndAccessCleanup>(access);
3481+
subjectMV = ManagedValue::forBorrowedAddressRValue(access);
3482+
} else {
3483+
subjectMV = B.createBeginBorrow(S, subjectMV,
3484+
false, /*fixed*/ true);
3485+
}
34723486
return {subjectMV, CastConsumptionKind::BorrowAlways};
34733487
}
34743488
llvm_unreachable("unhandled value ownership");

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureUtils.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,9 @@ bool Implementation::gatherUses(SILValue value) {
435435
continue;
436436
}
437437
case OperandOwnership::Borrow: {
438-
// Look through borrows.
439-
if (auto *bbi = dyn_cast<BeginBorrowInst>(nextUse->getUser())) {
438+
if (auto *bbi = dyn_cast<BeginBorrowInst>(nextUse->getUser());
439+
bbi && !bbi->isFixed()) {
440+
// Look through non-fixed borrows.
440441
LLVM_DEBUG(llvm::dbgs() << " Found recursive borrow!\n");
441442
for (auto *use : bbi->getUses()) {
442443
useWorklist.push_back(use);
@@ -452,7 +453,7 @@ bool Implementation::gatherUses(SILValue value) {
452453
}
453454

454455
// Otherwise, treat it as a normal use.
455-
LLVM_DEBUG(llvm::dbgs() << " Treating non-begin_borrow borrow as "
456+
LLVM_DEBUG(llvm::dbgs() << " Treating borrow as "
456457
"a non lifetime ending use!\n");
457458
blocksToUses.insert(nextUse->getParentBlock(),
458459
{nextUse,

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,11 +484,18 @@ eliminateSimpleBorrows(BeginBorrowInst *bbi, CanonicalizeInstruction &pass) {
484484
if (bbi->isLexical() && (bbi->getModule().getStage() == SILStage::Raw ||
485485
!isNestedLexicalBeginBorrow(bbi)))
486486
return next;
487+
488+
// Fixed borrow scopes can't be eliminated during the raw stage since they
489+
// control move checker behavior.
490+
if (bbi->isFixed() && bbi->getModule().getStage() == SILStage::Raw) {
491+
return next;
492+
}
487493

488494
// Borrow scopes representing a VarDecl can't be eliminated during the raw
489495
// stage because they may be needed for diagnostics.
490-
if (bbi->isFromVarDecl() && (bbi->getModule().getStage() == SILStage::Raw))
496+
if (bbi->isFromVarDecl() && bbi->getModule().getStage() == SILStage::Raw) {
491497
return next;
498+
}
492499

493500
// We know that our borrow is completely within the lifetime of its base value
494501
// if the borrow is never reborrowed. We check for reborrows and do not

0 commit comments

Comments
 (0)