@@ -601,13 +601,74 @@ void SILBuilder::emitScopedBorrowOperation(SILLocation loc, SILValue original,
601
601
createEndBorrow (loc, value);
602
602
}
603
603
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
+
604
663
CheckedCastBranchInst *SILBuilder::createCheckedCastBranch (
605
664
SILLocation Loc, bool isExact, SILValue op,
606
665
SILType destLoweredTy, CanType destFormalTy,
607
666
SILBasicBlock *successBB, SILBasicBlock *failureBB,
608
667
ProfileCounter target1Count, ProfileCounter target2Count) {
668
+ auto forwardingOwnership =
669
+ deriveForwardingOwnership (op, destLoweredTy, getFunction ());
609
670
return createCheckedCastBranch (Loc, isExact, op, destLoweredTy, destFormalTy,
610
- successBB, failureBB, op. getOwnershipKind () ,
671
+ successBB, failureBB, forwardingOwnership ,
611
672
target1Count, target2Count);
612
673
}
613
674
@@ -619,10 +680,11 @@ CheckedCastBranchInst *SILBuilder::createCheckedCastBranch(
619
680
assert ((!hasOwnership () || !failureBB->getNumArguments () ||
620
681
failureBB->getArgument (0 )->getType () == op->getType ()) &&
621
682
" failureBB's argument doesn't match incoming argument type" );
683
+
622
684
return insertTerminator (CheckedCastBranchInst::create (
623
685
getSILDebugLocation (Loc), isExact, op, destLoweredTy, destFormalTy,
624
- successBB, failureBB, getFunction (), target1Count,
625
- target2Count, forwardingOwnershipKind));
686
+ successBB, failureBB, getFunction (), target1Count, target2Count,
687
+ forwardingOwnershipKind));
626
688
}
627
689
628
690
void SILBuilderWithScope::insertAfter (SILInstruction *inst,
0 commit comments