Skip to content

Commit 8f53a92

Browse files
committed
SILGen OSSA support for switch_enum/checked_cast_br, related cleanup
Use APIs for creating terminator results that handle forwarding ownership consistently. Add ManagedValue::forForwardedRValue(SILValue) to handle cleanups consistently based on ownership forwarding. Add SILGenBuilder::createForwardedTermResult(SILType type) for creating termator results with the correct ownership and cleanups. Add SILGenBuilder::createTermResult(SILType type, ValueOwnershipKind ownership) that handles cleanup based on terminator result ownership. Add SILGenBuilder::createOptionalSomeResult(SwitchEnumInst) so a lot of code doesn't need to deal with unwrapping Optional types, terminator results, and ownership rules. Replace the existing "phi" APIs with a single SILGenBuilder::createPhi(SILType, ValueOwnershipKind) that handles cleanup based on phi ownership. Phis and terminator results are fundamentally different and need to be handled differently everywhere. Remove the confusion where terminator results were generated with a "phi argument" API.
1 parent 86c6a46 commit 8f53a92

16 files changed

+199
-138
lines changed

lib/SILGen/ManagedValue.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@
2222
using namespace swift;
2323
using namespace Lowering;
2424

25+
ManagedValue ManagedValue::forForwardedRValue(SILGenFunction &SGF,
26+
SILValue value) {
27+
if (!value)
28+
return ManagedValue();
29+
30+
switch (value->getOwnershipKind()) {
31+
case OwnershipKind::Any:
32+
llvm_unreachable("Invalid ownership for value");
33+
34+
case OwnershipKind::Owned:
35+
return ManagedValue(value, SGF.enterDestroyCleanup(value));
36+
37+
case OwnershipKind::Guaranteed:
38+
case OwnershipKind::None:
39+
case OwnershipKind::Unowned:
40+
return ManagedValue::forUnmanaged(value);
41+
}
42+
}
43+
2544
/// Emit a copy of this value with independent ownership.
2645
ManagedValue ManagedValue::copy(SILGenFunction &SGF, SILLocation loc) const {
2746
auto &lowering = SGF.getTypeLowering(getType());

lib/SILGen/ManagedValue.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ class ManagedValue {
9191
return ManagedValue(value, false, CleanupHandle::invalid());
9292
}
9393

94+
/// Create a managed value for a SILValue whose ownership is
95+
/// forwarded. Creates a new cleanup for +1 values. Forwarded +0 values
96+
/// require no cleanup.
97+
///
98+
/// Use this for values that do not introduce a new borrow scope. This is
99+
/// correct for casts and terminator results, not for phis.
100+
static ManagedValue forForwardedRValue(SILGenFunction &SGF, SILValue value);
101+
94102
/// Create a managed value for a +1 rvalue object.
95103
static ManagedValue forOwnedObjectRValue(SILValue value,
96104
CleanupHandle cleanup) {

lib/SILGen/ResultPlan.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -667,9 +667,9 @@ class ForeignAsyncInitializationPlan final : public ResultPlan {
667667

668668
auto errorTy = SGF.getASTContext().getErrorDecl()->getDeclaredType()
669669
->getCanonicalType();
670-
auto errorVal
671-
= SGF.B.createOwnedPhiArgument(SILType::getPrimitiveObjectType(errorTy));
672-
670+
auto errorVal = SGF.B.createTermResult(
671+
SILType::getPrimitiveObjectType(errorTy), OwnershipKind::Owned);
672+
673673
SGF.emitThrow(loc, errorVal, true);
674674
}
675675

lib/SILGen/SILGenBridging.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,17 +1715,15 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
17151715
{getASTContext().getOptionalSomeDecl(), hasCompletionBB},
17161716
{getASTContext().getOptionalNoneDecl(), noCompletionBB},
17171717
};
1718-
1719-
B.createSwitchEnum(loc, completionBlock, nullptr, dests);
1720-
1718+
1719+
auto *switchEnum =
1720+
B.createSwitchEnum(loc, completionBlock, nullptr, dests);
1721+
17211722
B.emitBlock(noCompletionBB);
17221723
B.createBranch(loc, doneBBOrNull);
17231724

17241725
B.emitBlock(hasCompletionBB);
1725-
completionBlock = hasCompletionBB->createPhiArgument(
1726-
SILType::getPrimitiveObjectType(completionTy),
1727-
OwnershipKind::Guaranteed);
1728-
1726+
completionBlock = switchEnum->createOptionalSomeResult();
17291727
}
17301728
};
17311729

lib/SILGen/SILGenBuilder.cpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -187,23 +187,38 @@ ManagedValue SILGenBuilder::createCopyValue(SILLocation loc,
187187
}
188188
#include "swift/AST/ReferenceStorage.def"
189189

190-
ManagedValue SILGenBuilder::createOwnedPhiArgument(SILType type) {
191-
SILPhiArgument *arg =
192-
getInsertionBB()->createPhiArgument(type, OwnershipKind::Owned);
193-
return SGF.emitManagedRValueWithCleanup(arg);
190+
ManagedValue SILGenBuilder::createForwardedTermResult(SILType type) {
191+
auto *succBB = getInsertionBB();
192+
auto *term = cast<OwnershipForwardingTermInst>(
193+
succBB->getSinglePredecessorBlock()->getTerminator());
194+
auto *arg = term->createResult(succBB, type);
195+
return ManagedValue::forForwardedRValue(SGF, arg);
194196
}
195197

196-
ManagedValue SILGenBuilder::createGuaranteedPhiArgument(SILType type) {
197-
SILPhiArgument *arg =
198-
getInsertionBB()->createPhiArgument(type, OwnershipKind::Guaranteed);
199-
return SGF.emitManagedBorrowedArgumentWithCleanup(arg);
198+
ManagedValue SILGenBuilder::createTermResult(SILType type,
199+
ValueOwnershipKind ownership) {
200+
// Despite the name, 'arg' is a terminator result, not a phi.
201+
auto *arg = getInsertionBB()->createPhiArgument(type, ownership);
202+
return ManagedValue::forForwardedRValue(SGF, arg);
200203
}
201204

202-
ManagedValue
203-
SILGenBuilder::createGuaranteedTransformingTerminatorArgument(SILType type) {
204-
SILPhiArgument *arg =
205-
getInsertionBB()->createPhiArgument(type, OwnershipKind::Guaranteed);
206-
return ManagedValue::forUnmanaged(arg);
205+
ManagedValue SILGenBuilder::createPhi(SILType type,
206+
ValueOwnershipKind ownership) {
207+
SILPhiArgument *arg = getInsertionBB()->createPhiArgument(type, ownership);
208+
switch (ownership) {
209+
case OwnershipKind::Any:
210+
llvm_unreachable("Invalid ownership for value");
211+
212+
case OwnershipKind::Owned:
213+
return SGF.emitManagedRValueWithCleanup(arg);
214+
215+
case OwnershipKind::Guaranteed:
216+
return SGF.emitManagedBorrowedArgumentWithCleanup(arg);
217+
218+
case OwnershipKind::None:
219+
case OwnershipKind::Unowned:
220+
return ManagedValue::forUnmanaged(arg);
221+
}
207222
}
208223

209224
ManagedValue SILGenBuilder::createAllocRef(

lib/SILGen/SILGenBuilder.h

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,34 @@ class SILGenBuilder : public SILBuilder {
125125
ManagedValue originalValue);
126126
#include "swift/AST/ReferenceStorage.def"
127127

128-
ManagedValue createOwnedPhiArgument(SILType type);
129-
ManagedValue createGuaranteedPhiArgument(SILType type);
128+
/// Create the block argument for an OwnershipForwardingTermInst result
129+
/// (checked_cast_br or switch_enum). Allows creating terminator
130+
/// results separately from creating the terminator. Alternatively, the result
131+
/// can be directly created as follows:
132+
///
133+
/// ManagedValue::forForwardedRValue(term->createResult(succBB, resultTy))
134+
///
135+
/// For a switch_enum with a default payload, use:
136+
///
137+
/// ManagedValue::forForwardedRValue(switchEnum->createDefaultResult())
138+
///
139+
ManagedValue createForwardedTermResult(SILType type);
130140

131-
/// For arguments from terminators that are "transforming terminators". These
132-
/// types of guaranteed arguments are validated as part of the operand of the
133-
/// transforming terminator since transforming terminators are guaranteed to
134-
/// be the only predecessor of our parent block.
141+
/// Create a terminator result with specified ownership.
135142
///
136-
/// NOTE: Two examples of transforming terminators are switch_enum,
137-
/// checked_cast_br.
138-
ManagedValue createGuaranteedTransformingTerminatorArgument(SILType type);
143+
/// Typically for an apply's return or error value, which should use
144+
/// OwnershipKind::Owned. For OwnershipForwardingTermInst (checked_cast_br or
145+
/// switch_enum), use createForwardedTermResult instead.
146+
ManagedValue createTermResult(SILType type, ValueOwnershipKind ownership);
147+
148+
/// Create the block argument for an Optional switch_enum.
149+
ManagedValue createOptionalSomeResult(SwitchEnumInst *switchEnum) {
150+
return ManagedValue::forForwardedRValue(
151+
SGF, switchEnum->createOptionalSomeResult());
152+
}
153+
154+
// Create the block argument for a phi.
155+
ManagedValue createPhi(SILType type, ValueOwnershipKind ownership);
139156

140157
using SILBuilder::createMarkUninitialized;
141158
ManagedValue createMarkUninitialized(ValueDecl *decl, ManagedValue operand,

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,8 +1533,8 @@ static ManagedValue emitBuiltinWithUnsafeContinuation(
15331533

15341534
auto errorTy = SGF.getASTContext().getErrorDecl()->getDeclaredType()
15351535
->getCanonicalType();
1536-
auto errorVal
1537-
= SGF.B.createOwnedPhiArgument(SILType::getPrimitiveObjectType(errorTy));
1536+
auto errorVal = SGF.B.createTermResult(
1537+
SILType::getPrimitiveObjectType(errorTy), OwnershipKind::Owned);
15381538

15391539
SGF.emitThrow(loc, errorVal, true);
15401540
}

lib/SILGen/SILGenConvert.cpp

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,9 @@ SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
198198

199199
// If we have an object, make sure the object is at +1. All switch_enum of
200200
// objects is done at +1.
201-
if (optional.getType().isAddress()) {
201+
bool isAddress = optional.getType().isAddress();
202+
SwitchEnumInst *switchEnum = nullptr;
203+
if (isAddress) {
202204
// We forward in the creation routine for
203205
// unchecked_take_enum_data_addr. switch_enum_addr is a +0 operation.
204206
B.createSwitchEnumAddr(loc, optional.getValue(),
@@ -208,9 +210,9 @@ SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
208210
optional = optional.ensurePlusOne(*this, loc);
209211
hadCleanup = true;
210212
hadLValue = false;
211-
B.createSwitchEnum(loc, optional.forward(*this),
212-
/*defaultDest*/ nullptr,
213-
{{someDecl, contBB}, {noneDecl, failBB}});
213+
switchEnum = B.createSwitchEnum(loc, optional.forward(*this),
214+
/*defaultDest*/ nullptr,
215+
{{someDecl, contBB}, {noneDecl, failBB}});
214216
}
215217
B.emitBlock(failBB);
216218

@@ -241,13 +243,12 @@ SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
241243
B.emitBlock(contBB);
242244

243245
ManagedValue result;
244-
SILType payloadType = optional.getType().getOptionalObjectType();
245-
246-
if (payloadType.isObject()) {
247-
result = B.createOwnedPhiArgument(payloadType);
248-
} else {
246+
if (isAddress) {
247+
SILType payloadType = optional.getType().getOptionalObjectType();
249248
result =
250249
B.createUncheckedTakeEnumDataAddr(loc, optional, someDecl, payloadType);
250+
} else {
251+
result = B.createOptionalSomeResult(switchEnum);
251252
}
252253

253254
if (hadCleanup) {
@@ -415,15 +416,14 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
415416
// If the result is address-only, we need to return something in memory,
416417
// otherwise the result is the BBArgument in the merge point.
417418
// TODO: use the SGFContext passed in.
418-
ManagedValue finalResult;
419-
if (resultTL.isAddressOnly() && silConv.useLoweredAddresses()) {
420-
finalResult = emitManagedBufferWithCleanup(
419+
ManagedValue resultAddress;
420+
bool addressOnly = resultTL.isAddressOnly() && silConv.useLoweredAddresses();
421+
if (addressOnly) {
422+
resultAddress = emitManagedBufferWithCleanup(
421423
emitTemporaryAllocation(loc, resultTy), resultTL);
422-
} else {
423-
SILGenSavedInsertionPoint IP(*this, contBB);
424-
finalResult = B.createOwnedPhiArgument(resultTL.getLoweredType());
425424
}
426425

426+
ValueOwnershipKind resultOwnership = OwnershipKind::Any;
427427
SEBuilder.addOptionalSomeCase(
428428
isPresentBB, contBB, [&](ManagedValue input, SwitchCaseFullExpr &&scope) {
429429
// If we have an address only type, we want to match the old behavior of
@@ -439,36 +439,42 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc,
439439

440440
ManagedValue result = transformValue(*this, loc, input, noOptResultTy,
441441
SGFContext());
442-
443-
if (!(resultTL.isAddressOnly() && silConv.useLoweredAddresses())) {
442+
resultOwnership = result.getValue()->getOwnershipKind();
443+
if (!addressOnly) {
444444
SILValue some = B.createOptionalSome(loc, result).forward(*this);
445445
return scope.exitAndBranch(loc, some);
446446
}
447447

448448
RValue R(*this, loc, noOptResultTy.getASTType(), result);
449449
ArgumentSource resultValueRV(loc, std::move(R));
450450
emitInjectOptionalValueInto(loc, std::move(resultValueRV),
451-
finalResult.getValue(), resultTL);
451+
resultAddress.getValue(), resultTL);
452452
return scope.exitAndBranch(loc);
453453
});
454454

455455
SEBuilder.addOptionalNoneCase(
456456
isNotPresentBB, contBB,
457457
[&](ManagedValue input, SwitchCaseFullExpr &&scope) {
458-
if (!(resultTL.isAddressOnly() && silConv.useLoweredAddresses())) {
458+
if (!addressOnly) {
459459
SILValue none =
460460
B.createManagedOptionalNone(loc, resultTy).forward(*this);
461461
return scope.exitAndBranch(loc, none);
462462
}
463463

464-
emitInjectOptionalNothingInto(loc, finalResult.getValue(), resultTL);
464+
emitInjectOptionalNothingInto(loc, resultAddress.getValue(), resultTL);
465465
return scope.exitAndBranch(loc);
466466
});
467467

468468
std::move(SEBuilder).emit();
469469

470470
B.emitBlock(contBB);
471-
return finalResult;
471+
if (addressOnly)
472+
return resultAddress;
473+
474+
// This phi's ownership is derived from the transformed value's
475+
// ownership, not the input ownership. Transformation can convert a value with
476+
// no ownership to an owned value.
477+
return B.createPhi(resultTL.getLoweredType(), resultOwnership);
472478
}
473479

474480
SILGenFunction::OpaqueValueRAII::~OpaqueValueRAII() {
@@ -712,8 +718,9 @@ ManagedValue SILGenFunction::emitExistentialErasure(
712718
{ ctx.getOptionalSomeDecl(), isPresentBB },
713719
{ ctx.getOptionalNoneDecl(), isNotPresentBB }
714720
};
715-
B.createSwitchEnum(loc, potentialNSError.forward(*this),
716-
/*default*/ nullptr, cases);
721+
auto *switchEnum =
722+
B.createSwitchEnum(loc, potentialNSError.forward(*this),
723+
/*default*/ nullptr, cases);
717724

718725
// If we did get an NSError, emit the existential erasure from that
719726
// NSError.
@@ -726,9 +733,7 @@ ManagedValue SILGenFunction::emitExistentialErasure(
726733

727734
// Receive the error value. It's typed as an 'AnyObject' for
728735
// layering reasons, so perform an unchecked cast down to NSError.
729-
SILType anyObjectTy =
730-
potentialNSError.getType().getOptionalObjectType();
731-
ManagedValue nsError = B.createOwnedPhiArgument(anyObjectTy);
736+
auto nsError = B.createOptionalSomeResult(switchEnum);
732737
nsError = B.createUncheckedRefCast(loc, nsError,
733738
getLoweredType(nsErrorType));
734739

lib/SILGen/SILGenDistributed.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -622,19 +622,18 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
622622
auto resolve =
623623
switchBB->createPhiArgument(optionalReturnTy, OwnershipKind::Owned);
624624

625-
B.createSwitchEnum(
625+
auto *switchEnum = B.createSwitchEnum(
626626
loc, resolve, nullptr,
627627
{{C.getOptionalSomeDecl(), resolvedBB},
628628
{std::make_pair(C.getOptionalNoneDecl(), makeProxyBB)}});
629+
switchEnum->createOptionalSomeResult();
629630
}
630631

631632
// ==== Case 'some') return the resolved instance
632633
{
633634
B.emitBlock(resolvedBB);
634635

635-
auto local = resolvedBB->createPhiArgument(returnTy, OwnershipKind::Owned);
636-
637-
B.createBranch(loc, returnBB, {local});
636+
B.createBranch(loc, returnBB, {resolvedBB->getArgument(0)});
638637
}
639638

640639
// ==== Case 'none') Create the remote instance
@@ -1016,4 +1015,4 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
10161015
Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind);
10171016
B.createThrow(loc, error);
10181017
}
1019-
}
1018+
}

0 commit comments

Comments
 (0)