Skip to content

Commit 86c6a46

Browse files
committed
SILBuilder SIL support forwarding ownership on terminators.
1 parent 0cfe74b commit 86c6a46

File tree

2 files changed

+73
-8
lines changed

2 files changed

+73
-8
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,6 +2221,11 @@ class SILBuilder {
22212221
BranchInst *createBranch(SILLocation Loc, SILBasicBlock *TargetBlock,
22222222
OperandValueArrayRef Args);
22232223

2224+
// This only creates the terminator, not the results. Create the results with
2225+
// OwnershipForwardingTermInst::createResult() and
2226+
// SwitchEnumInst::createDefaultResult() to ensure that the result ownership
2227+
// is correct (it must be consistent with the switch_enum's forwarding
2228+
// ownership, which may differ from \p Operand's ownership).
22242229
SwitchValueInst *
22252230
createSwitchValue(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
22262231
ArrayRef<std::pair<SILValue, SILBasicBlock *>> CaseBBs) {
@@ -2232,16 +2237,14 @@ class SILBuilder {
22322237
SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
22332238
ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
22342239
Optional<ArrayRef<ProfileCounter>> CaseCounts = None,
2235-
ProfileCounter DefaultCount = ProfileCounter()) {
2236-
return createSwitchEnum(Loc, Operand, DefaultBB, CaseBBs, CaseCounts,
2237-
DefaultCount, Operand.getOwnershipKind());
2238-
}
2240+
ProfileCounter DefaultCount = ProfileCounter());
22392241

22402242
SwitchEnumInst *createSwitchEnum(
22412243
SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
22422244
ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
22432245
Optional<ArrayRef<ProfileCounter>> CaseCounts,
2244-
ProfileCounter DefaultCount, ValueOwnershipKind forwardingOwnershipKind) {
2246+
ProfileCounter DefaultCount,
2247+
ValueOwnershipKind forwardingOwnershipKind) {
22452248
return insertTerminator(SwitchEnumInst::create(
22462249
getSILDebugLocation(Loc), Operand, DefaultBB, CaseBBs, getFunction(),
22472250
CaseCounts, DefaultCount, forwardingOwnershipKind));

lib/SIL/IR/SILBuilder.cpp

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,13 +601,74 @@ void SILBuilder::emitScopedBorrowOperation(SILLocation loc, SILValue original,
601601
createEndBorrow(loc, value);
602602
}
603603

604+
/// Attempt to propagate ownership from \p operand to the returned forwarding
605+
/// ownership where the forwarded value has type \p targetType. If this fails,
606+
/// return Owned forwarding ownership instead.
607+
///
608+
/// Propagation only fails when \p operand is dynamically trivial, as indicated
609+
/// by ownership None, AND \p targetType is statically nontrivial.
610+
///
611+
/// Example:
612+
///
613+
/// %e = enum $Optional<AnyObject>, #Optional.none!enumelt
614+
/// switch_enum %e : $Optional<AnyObject>,
615+
/// case #Optional.some!enumelt: bb2...,
616+
/// forwarding: @owned
617+
/// bb2(%arg : @owned AnyObject):
618+
///
619+
/// Example:
620+
///
621+
/// %mt = metatype $@thick C.Type
622+
/// checked_cast_br %mt : $@thick C.Type to AnyObject.Type, bb1, bb2,
623+
/// forwarding: @owned
624+
/// bb1(%arg : @owned AnyObject.Type):
625+
///
626+
/// If the forwarded value is statically known nontrivial, then the forwarding
627+
/// ownership cannot be None. Such a result is unreachable, but the SIL on that
628+
/// path must still be valid. When creating ownership out of thin air, default
629+
/// to Owned because that allows the value to be consumed without generating a
630+
/// copy. This does require the client code to handle ending the lifetime of an
631+
/// owned result even if the input was passed as guaranteed.
632+
///
633+
/// Note: For simplicitly, ownership None is not propagated for any statically
634+
/// nontrivial result, even if \p targetType may also be dynamically
635+
/// trivial. For example, the operand of a switch_enum could be a nested enum
636+
/// such that all switch cases may be dynamically trivial. Or a checked_cast_br
637+
/// could cast from one dynamically trivial enum to another. Figuring out
638+
/// whether the dynamically trivial operand value maps onto a dynamically
639+
/// trivial terminator result would be very complex with no practical benefit.
640+
static ValueOwnershipKind deriveForwardingOwnership(SILValue operand,
641+
SILType targetType,
642+
SILFunction &func) {
643+
if (operand.getOwnershipKind() != OwnershipKind::None
644+
|| targetType.isTrivial(func)) {
645+
return operand.getOwnershipKind();
646+
}
647+
return OwnershipKind::Owned;
648+
}
649+
650+
SwitchEnumInst *SILBuilder::createSwitchEnum(
651+
SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
652+
ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
653+
Optional<ArrayRef<ProfileCounter>> CaseCounts,
654+
ProfileCounter DefaultCount) {
655+
// Consider the operand's type to be the target's type since a switch
656+
// covers all cases including the default argument.
657+
auto forwardingOwnership =
658+
deriveForwardingOwnership(Operand, Operand->getType(), getFunction());
659+
return createSwitchEnum(Loc, Operand, DefaultBB, CaseBBs, CaseCounts,
660+
DefaultCount, forwardingOwnership);
661+
}
662+
604663
CheckedCastBranchInst *SILBuilder::createCheckedCastBranch(
605664
SILLocation Loc, bool isExact, SILValue op,
606665
SILType destLoweredTy, CanType destFormalTy,
607666
SILBasicBlock *successBB, SILBasicBlock *failureBB,
608667
ProfileCounter target1Count, ProfileCounter target2Count) {
668+
auto forwardingOwnership =
669+
deriveForwardingOwnership(op, destLoweredTy, getFunction());
609670
return createCheckedCastBranch(Loc, isExact, op, destLoweredTy, destFormalTy,
610-
successBB, failureBB, op.getOwnershipKind(),
671+
successBB, failureBB, forwardingOwnership,
611672
target1Count, target2Count);
612673
}
613674

@@ -619,10 +680,11 @@ CheckedCastBranchInst *SILBuilder::createCheckedCastBranch(
619680
assert((!hasOwnership() || !failureBB->getNumArguments() ||
620681
failureBB->getArgument(0)->getType() == op->getType()) &&
621682
"failureBB's argument doesn't match incoming argument type");
683+
622684
return insertTerminator(CheckedCastBranchInst::create(
623685
getSILDebugLocation(Loc), isExact, op, destLoweredTy, destFormalTy,
624-
successBB, failureBB, getFunction(), target1Count,
625-
target2Count, forwardingOwnershipKind));
686+
successBB, failureBB, getFunction(), target1Count, target2Count,
687+
forwardingOwnershipKind));
626688
}
627689

628690
void SILBuilderWithScope::insertAfter(SILInstruction *inst,

0 commit comments

Comments
 (0)