@@ -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+
604663CheckedCastBranchInst *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
628690void SILBuilderWithScope::insertAfter (SILInstruction *inst,
0 commit comments