Skip to content

Commit dc56f8e

Browse files
committed
[SILGen] emit local variable scopes for trivial values.
Required for SIL analysis of local variable scopes. For example, to track lifetime dependence on a variable. Example: .swift: func foo(i: Int) { let v = i .sil: %1 = move_value [var_decl] %0 : $Int // starts the variable scope extend_lifetime %1 : $Int // ends the variable scope Rewrite getValueForLexicalLifetimeBinding. The previous implementation was incomprehensible to me. This will potentially change functionality by removing previous corner cases that look like nonsense to me. Adds an unfortunate FIXME to allow migration without affecting fake metatype locals produced by function conversion!
1 parent 3316a58 commit dc56f8e

File tree

1 file changed

+102
-128
lines changed

1 file changed

+102
-128
lines changed

lib/SILGen/SILGenDecl.cpp

Lines changed: 102 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -756,16 +756,16 @@ class LetValueInitialization : public Initialization {
756756
address = SGF.B.createMarkUninitializedVar(vd, address);
757757
DestroyCleanup = SGF.enterDormantTemporaryCleanup(address, *lowering);
758758
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(address);
759-
} else if (!lowering->isTrivial()) {
760-
// Push a cleanup to destroy the let declaration. This has to be
761-
// inactive until the variable is initialized: if control flow exits the
762-
// before the value is bound, we don't want to destroy the value.
763-
SGF.Cleanups.pushCleanupInState<DestroyLocalVariable>(
764-
CleanupState::Dormant, vd);
765-
DestroyCleanup = SGF.Cleanups.getTopCleanup();
766-
} else {
767-
DestroyCleanup = CleanupHandle::invalid();
768759
}
760+
// Push a cleanup to destroy the let declaration. This has to be
761+
// inactive until the variable is initialized: if control flow exits the
762+
// before the value is bound, we don't want to destroy the value.
763+
//
764+
// Cleanups are required for all lexically scoped variables to delimite
765+
// the variable scope, even if the cleanup does nothing.
766+
SGF.Cleanups.pushCleanupInState<DestroyLocalVariable>(
767+
CleanupState::Dormant, vd);
768+
DestroyCleanup = SGF.Cleanups.getTopCleanup();
769769
}
770770

771771
~LetValueInitialization() override {
@@ -810,50 +810,26 @@ class LetValueInitialization : public Initialization {
810810
SplitCleanups);
811811
}
812812

813-
/// This is a helper method for bindValue that handles any changes to the
814-
/// value needed for lexical lifetime or no implicit copy purposes.
813+
/// This is a helper method for bindValue that creates a scopes operation for
814+
/// the lexical variable lifetime and handles any changes to the value needed
815+
/// for move-only values.
815816
SILValue getValueForLexicalLifetimeBinding(SILGenFunction &SGF,
816817
SILLocation PrologueLoc,
817818
SILValue value, bool wasPlusOne) {
818-
// If we have none...
819-
if (value->getOwnershipKind() == OwnershipKind::None) {
820-
// Then check if we have a pure move only type. In that case, we need to
821-
// insert a no implicit copy
822-
if (value->getType().isMoveOnly(/*orWrapped=*/false)) {
823-
value = SGF.B.createMoveValue(PrologueLoc, value, IsLexical);
824-
return SGF.B.createMarkUnresolvedNonCopyableValueInst(
825-
PrologueLoc, value,
826-
MarkUnresolvedNonCopyableValueInst::CheckKind::
827-
ConsumableAndAssignable);
828-
}
829-
830-
// If we have a no implicit copy trivial type, wrap it in the move only
831-
// wrapper and mark it as needing checking by the move checker.
832-
if (vd->isNoImplicitCopy() && value->getType().isTrivial(SGF.F)) {
833-
value =
834-
SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(PrologueLoc, value);
835-
value = SGF.B.createMoveValue(PrologueLoc, value, IsLexical);
836-
return SGF.B.createMarkUnresolvedNonCopyableValueInst(
837-
PrologueLoc, value,
838-
MarkUnresolvedNonCopyableValueInst::CheckKind::
839-
ConsumableAndAssignable);
840-
}
841-
842-
if (!value->getType().isTrivial(SGF.F)) {
843-
// A value without ownership of non-trivial type, e.g. Optional<K>.none.
844-
// Mark that it is from a VarDecl.
845-
return SGF.B.createMoveValue(PrologueLoc, value, IsNotLexical,
846-
DoesNotHavePointerEscape, IsFromVarDecl);
847-
}
848-
819+
// TODO: emitPatternBindingInitialization creates fake local variables for
820+
// metatypes within function_conversion expressions that operate on static
821+
// functions. Creating SIL local variables for all these is impractical and
822+
// undesirable. We need a better way of representing these "capture_list"
823+
// locals in a way that doesn't produce SIL locals. For now, bypassing
824+
// metatypes mostly avoids the issue, but it's not robust and doesn't allow
825+
// SIL-level analysis of real metatype variables.
826+
if (isa<MetatypeType>(value->getType().getASTType())) {
849827
return value;
850828
}
851829

852-
// Otherwise, we need to perform some additional processing. First, if we
853-
// have an owned moveonly value that had a cleanup, then create a move_value
854-
// that acts as a consuming use of the value. The reason why we want this is
855-
// even if we are only performing a borrow for our lexical lifetime, we want
856-
// to ensure that our defs see this initialization as consuming this value.
830+
// Preprocess an owned moveonly value that had a cleanup. Even if we are
831+
// only performing a borrow for our lexical lifetime, this ensures that
832+
// defs see this initialization as consuming this value.
857833
if (value->getOwnershipKind() == OwnershipKind::Owned &&
858834
value->getType().isMoveOnlyWrapped()) {
859835
assert(wasPlusOne);
@@ -864,50 +840,35 @@ class LetValueInitialization : public Initialization {
864840
value =
865841
SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(PrologueLoc, value);
866842
}
867-
868-
// If we still have a trivial thing, just return that.
869-
if (value->getType().isTrivial(SGF.F))
870-
return value;
871-
872-
// Check if we have a move only type. In that case, we perform a lexical
873-
// move and insert a mark_unresolved_non_copyable_value.
874-
//
875-
// We do this before the begin_borrow "normal" path below since move only
876-
// types do not have no implicit copy attr on them.
877-
if (value->getOwnershipKind() == OwnershipKind::Owned &&
878-
value->getType().isMoveOnly(/*orWrapped=*/false)) {
879-
value = SGF.B.createMoveValue(PrologueLoc, value, IsLexical);
880-
return SGF.B.createMarkUnresolvedNonCopyableValueInst(
881-
PrologueLoc, value,
882-
MarkUnresolvedNonCopyableValueInst::CheckKind::
883-
ConsumableAndAssignable);
843+
auto isLexical =
844+
IsLexical_t(SGF.F.getLifetime(vd, value->getType()).isLexical());
845+
switch (value->getOwnershipKind()) {
846+
case OwnershipKind::None:
847+
case OwnershipKind::Owned:
848+
value = SGF.B.createMoveValue(PrologueLoc, value, isLexical,
849+
DoesNotHavePointerEscape, IsFromVarDecl);
850+
break;
851+
case OwnershipKind::Guaranteed:
852+
value = SGF.B.createBeginBorrow(PrologueLoc, value, isLexical,
853+
DoesNotHavePointerEscape, IsFromVarDecl);
854+
break;
855+
case OwnershipKind::Unowned:
856+
case OwnershipKind::Any:
857+
llvm_unreachable("unexpected ownership");
884858
}
885-
886-
// If we have a no implicit copy lexical, emit the instruction stream so
887-
// that the move checker knows to check this variable.
888859
if (vd->isNoImplicitCopy()) {
889-
value = SGF.B.createMoveValue(PrologueLoc, value, IsLexical,
890-
DoesNotHavePointerEscape, IsFromVarDecl);
891860
value =
892861
SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(PrologueLoc, value);
893-
return SGF.B.createMarkUnresolvedNonCopyableValueInst(
894-
PrologueLoc, value,
895-
MarkUnresolvedNonCopyableValueInst::CheckKind::
896-
ConsumableAndAssignable);
862+
// fall-through to the owned move-only case...
897863
}
898-
899-
// Otherwise, if we do not have a no implicit copy variable, just follow
900-
// the "normal path".
901-
902-
auto isLexical =
903-
IsLexical_t(SGF.F.getLifetime(vd, value->getType()).isLexical());
904-
905-
if (value->getOwnershipKind() == OwnershipKind::Owned)
906-
return SGF.B.createMoveValue(PrologueLoc, value, isLexical,
907-
DoesNotHavePointerEscape, IsFromVarDecl);
908-
909-
return SGF.B.createBeginBorrow(PrologueLoc, value, isLexical,
910-
DoesNotHavePointerEscape, IsFromVarDecl);
864+
if (value->getType().isMoveOnly(/*orWrapped=*/true)
865+
&& value->getOwnershipKind() == OwnershipKind::Owned) {
866+
value = SGF.B.createMarkUnresolvedNonCopyableValueInst(
867+
PrologueLoc, value,
868+
MarkUnresolvedNonCopyableValueInst::CheckKind::
869+
ConsumableAndAssignable);
870+
}
871+
return value;
911872
}
912873

913874
void bindValue(SILValue value, SILGenFunction &SGF, bool wasPlusOne,
@@ -2336,23 +2297,37 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
23362297

23372298
assert(VarLocs.count(vd) && "var decl wasn't emitted?!");
23382299

2300+
auto emitEndBorrow = [this, silLoc](SILValue value){
2301+
if (value->getOwnershipKind() == OwnershipKind::None) {
2302+
B.createExtendLifetime(silLoc, value);
2303+
} else {
2304+
B.createEndBorrow(silLoc, value);
2305+
}
2306+
};
2307+
2308+
auto emitDestroy = [this, silLoc](SILValue value){
2309+
if (value->getOwnershipKind() == OwnershipKind::None) {
2310+
B.createExtendLifetime(silLoc, value);
2311+
} else {
2312+
B.emitDestroyValueOperation(silLoc, value);
2313+
}
2314+
};
2315+
23392316
auto loc = VarLocs[vd];
23402317

23412318
// For a heap variable, the box is responsible for the value. We just need
23422319
// to give up our retain count on it.
2343-
if (loc.box) {
2320+
if (auto boxValue = loc.box) {
23442321
if (!getASTContext().SILOpts.supportsLexicalLifetimes(getModule())) {
2345-
B.emitDestroyValueOperation(silLoc, loc.box);
2322+
emitDestroy(boxValue);
23462323
return;
23472324
}
23482325

2349-
if (auto *bbi = dyn_cast<BeginBorrowInst>(loc.box)) {
2350-
B.createEndBorrow(silLoc, bbi);
2351-
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
2352-
return;
2326+
if (auto *bbi = dyn_cast<BeginBorrowInst>(boxValue)) {
2327+
emitEndBorrow(bbi);
2328+
boxValue = bbi->getOperand();
23532329
}
2354-
2355-
B.emitDestroyValueOperation(silLoc, loc.box);
2330+
emitDestroy(boxValue);
23562331
return;
23572332
}
23582333

@@ -2366,73 +2341,72 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
23662341
}
23672342

23682343
if (!getASTContext().SILOpts.supportsLexicalLifetimes(getModule())) {
2369-
B.emitDestroyValueOperation(silLoc, Val);
2344+
emitDestroy(Val);
23702345
return;
23712346
}
23722347

2373-
if (Val->getOwnershipKind() == OwnershipKind::None) {
2348+
// If no variable scope was emitted, then we might not have a defining
2349+
// instruction.
2350+
if (!Val.getDefiningInstruction()) {
2351+
emitDestroy(Val);
23742352
return;
23752353
}
23762354

23772355
// This handles any case where we copy + begin_borrow or copyable_to_moveonly
23782356
// + begin_borrow. In either case we just need to end the lifetime of the
23792357
// begin_borrow's operand.
23802358
if (auto *bbi = dyn_cast<BeginBorrowInst>(Val.getDefiningInstruction())) {
2381-
B.createEndBorrow(silLoc, bbi);
2382-
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
2359+
emitEndBorrow(bbi);
2360+
emitDestroy(bbi->getOperand());
23832361
return;
23842362
}
23852363

23862364
if (auto *mvi = dyn_cast<MoveValueInst>(Val.getDefiningInstruction())) {
2387-
B.emitDestroyValueOperation(silLoc, mvi);
2365+
emitDestroy(mvi);
23882366
return;
23892367
}
23902368

2391-
if (auto *mvi = dyn_cast<MarkUnresolvedNonCopyableValueInst>(
2369+
// Handle BeginBorrow and MoveValue before bailing-out on trivial values.
2370+
if (Val->getOwnershipKind() == OwnershipKind::None) {
2371+
return;
2372+
}
2373+
2374+
if (auto *mark = dyn_cast<MarkUnresolvedNonCopyableValueInst>(
23922375
Val.getDefiningInstruction())) {
2393-
if (mvi->hasMoveCheckerKind()) {
2394-
if (auto *cvi = dyn_cast<CopyValueInst>(mvi->getOperand())) {
2376+
if (mark->hasMoveCheckerKind()) {
2377+
if (auto *cvi = dyn_cast<CopyValueInst>(mark->getOperand())) {
23952378
if (auto *bbi = dyn_cast<BeginBorrowInst>(cvi->getOperand())) {
2396-
if (bbi->isLexical()) {
2397-
B.emitDestroyValueOperation(silLoc, mvi);
2398-
B.createEndBorrow(silLoc, bbi);
2399-
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
2400-
return;
2401-
}
2379+
emitDestroy(mark);
2380+
emitEndBorrow(bbi);
2381+
emitDestroy(bbi->getOperand());
2382+
return;
24022383
}
24032384
}
24042385

24052386
if (auto *copyToMove = dyn_cast<CopyableToMoveOnlyWrapperValueInst>(
2406-
mvi->getOperand())) {
2407-
if (auto *move = dyn_cast<MoveValueInst>(copyToMove->getOperand())) {
2408-
if (move->isLexical()) {
2409-
B.emitDestroyValueOperation(silLoc, mvi);
2410-
return;
2411-
}
2387+
mark->getOperand())) {
2388+
if (copyToMove->getOperand()->isFromVarDecl()) {
2389+
emitDestroy(mark);
2390+
return;
24122391
}
24132392
}
24142393

2415-
if (auto *cvi = dyn_cast<ExplicitCopyValueInst>(mvi->getOperand())) {
2394+
if (auto *cvi = dyn_cast<ExplicitCopyValueInst>(mark->getOperand())) {
24162395
if (auto *bbi = dyn_cast<BeginBorrowInst>(cvi->getOperand())) {
2417-
if (bbi->isLexical()) {
2418-
B.emitDestroyValueOperation(silLoc, mvi);
2419-
B.createEndBorrow(silLoc, bbi);
2420-
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
2421-
return;
2422-
}
2396+
emitDestroy(mark);
2397+
emitEndBorrow(bbi);
2398+
emitDestroy(bbi->getOperand());
2399+
return;
24232400
}
24242401
}
24252402

24262403
// Handle trivial arguments.
2427-
if (auto *move = dyn_cast<MoveValueInst>(mvi->getOperand())) {
2428-
if (move->isLexical()) {
2429-
B.emitDestroyValueOperation(silLoc, mvi);
2430-
return;
2431-
}
2404+
if (auto *move = dyn_cast<MoveValueInst>(mark->getOperand())) {
2405+
emitDestroy(mark);
2406+
return;
24322407
}
24332408
}
2434-
}
2435-
2409+
}
24362410
llvm_unreachable("unhandled case");
24372411
}
24382412

0 commit comments

Comments
 (0)