@@ -226,6 +226,8 @@ struct OwnershipKind {
226226
227227llvm::raw_ostream &operator <<(llvm::raw_ostream &os, const OwnershipKind &kind);
228228
229+ enum class OperandOwnership ;
230+
229231// / A value representing the specific ownership semantics that a SILValue may
230232// / have.
231233struct ValueOwnershipKind {
@@ -286,6 +288,8 @@ struct ValueOwnershipKind {
286288 llvm_unreachable (" covered switch" );
287289 }
288290
291+ OperandOwnership getForwardingOperandOwnership () const ;
292+
289293 // / Returns true if \p Other can be merged successfully with this, implying
290294 // / that the two ownership kinds are "compatibile".
291295 // /
@@ -597,12 +601,6 @@ class OwnershipConstraint {
597601 return lifetimeConstraint;
598602 }
599603
600- // / Return a constraint that is appropriate for an operand that can accept a
601- // / value with any ownership kind without ending said value's lifetime.
602- static OwnershipConstraint any () {
603- return {OwnershipKind::Any, UseLifetimeConstraint::NonLifetimeEnding};
604- }
605-
606604 bool satisfiedBy (const Operand *use) const ;
607605
608606 bool satisfiesConstraint (ValueOwnershipKind testKind) const {
@@ -618,6 +616,124 @@ class OwnershipConstraint {
618616llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
619617 OwnershipConstraint constraint);
620618
619+ // / Categorize all uses in terms of their ownership effect.
620+ // /
621+ // / Used to verify completeness of the ownership use model and exhaustively
622+ // / switch over any category of ownership use. Implies ownership constraints and
623+ // / lifetime constraints.
624+ enum class OperandOwnership {
625+ // / Uses of ownership None. These uses are incompatible with values that have
626+ // / ownership but are otherwise not verified.
627+ None,
628+
629+ // / MARK: Uses of any ownership values:
630+
631+ // / Point-in-time use. Uses the value instantaneously.
632+ // / (copy_value, single-instruction apply with @guaranteed argument)
633+ InstantaneousUse,
634+ // FIXME: The PointerEscape category should be eliminated. All pointer escapes
635+ // should be InteriorPointer, guarded by a borrow scope.
636+ PointerEscape,
637+ // / Bitwise escape. Escapes the nontrivial contents of the value.
638+ // / OSSA does not enforce the lifetime of the escaping bits.
639+ // / The programmer must explicitly force lifetime extension.
640+ // / (ref_to_unowned, unchecked_trivial_bitcast)
641+ BitwiseEscape,
642+
643+ // / MARK: Uses of Unowned values:
644+
645+ // / Forwarding instruction with an Unowned result must have Unowned operands.
646+ ForwardingUnowned,
647+
648+ // / MARK: Uses of Owned values:
649+
650+ // / Borrow. Propagates the owned value within a scope, without consuming it.
651+ // / (begin_borrow, begin_apply with @guaranteed argument)
652+ Borrow,
653+ // / Destroying Consume. Destroys the owned value immediately.
654+ // / (store, destroy, @owned destructure).
655+ DestroyingConsume,
656+ // / Forwarding Consume. Consumes the owned value indirectly via a move.
657+ // / (br, destructure, tuple, struct, cast, switch).
658+ ForwardingConsume,
659+
660+ // / MARK: Uses of Guaranteed values:
661+
662+ // / Nested Borrow. Propagates the guaranteed value within a nested borrow
663+ // / scope, without ending the outer borrow scope, following stack discipline.
664+ // / (begin_borrow, begin_apply with @guaranteed).
665+ NestedBorrow,
666+ // / Interior Pointer. Propagates an address into the guaranteed value within
667+ // / the base's borrow scope. (ref_element_addr, open_existential_box)
668+ InteriorPointer,
669+ // / Forwarded Borrow. Propagates the guaranteed value within the base's
670+ // / borrow scope.
671+ // / (tuple_extract, struct_extract, cast, switch)
672+ ForwardingBorrow,
673+ // / End Borrow. End the borrow scope opened directly by the operand.
674+ // / The operand must be a begin_borrow, begin_apply, or function argument.
675+ // / (end_borrow, end_apply)
676+ EndBorrow,
677+ // Reborrow. Ends the borrow scope opened directly by the operand and begins
678+ // one or multiple disjoint borrow scopes. If a forwarded value is reborrowed,
679+ // then its base must also be reborrowed at the same point.
680+ // (br, FIXME: should also include destructure, tuple, struct)
681+ Reborrow
682+ };
683+
684+ llvm::raw_ostream &operator <<(llvm::raw_ostream &os, OperandOwnership operandOwnership);
685+
686+ // / Return the OwnershipConstraint for a OperandOwnership.
687+ // /
688+ // / Defined inline so the switch is eliminated for constant OperandOwnership.
689+ inline OwnershipConstraint
690+ getOwnershipConstraint (OperandOwnership operandOwnership) {
691+ switch (operandOwnership) {
692+ case OperandOwnership::None:
693+ return {OwnershipKind::None, UseLifetimeConstraint::NonLifetimeEnding};
694+ case OperandOwnership::InstantaneousUse:
695+ case OperandOwnership::PointerEscape:
696+ case OperandOwnership::BitwiseEscape:
697+ return {OwnershipKind::Any, UseLifetimeConstraint::NonLifetimeEnding};
698+ case OperandOwnership::ForwardingUnowned:
699+ return {OwnershipKind::Unowned, UseLifetimeConstraint::NonLifetimeEnding};
700+ case OperandOwnership::Borrow:
701+ return {OwnershipKind::Owned, UseLifetimeConstraint::NonLifetimeEnding};
702+ case OperandOwnership::DestroyingConsume:
703+ case OperandOwnership::ForwardingConsume:
704+ return {OwnershipKind::Owned, UseLifetimeConstraint::LifetimeEnding};
705+ case OperandOwnership::NestedBorrow:
706+ case OperandOwnership::InteriorPointer:
707+ case OperandOwnership::ForwardingBorrow:
708+ return {OwnershipKind::Guaranteed,
709+ UseLifetimeConstraint::NonLifetimeEnding};
710+ case OperandOwnership::EndBorrow:
711+ case OperandOwnership::Reborrow:
712+ return {OwnershipKind::Guaranteed, UseLifetimeConstraint::LifetimeEnding};
713+ }
714+ }
715+
716+ // Forwarding instructions have a dynamic ownership kind. Their forwarded
717+ // operand constraint depends on that dynamic result ownership. If the result is
718+ // owned, then the instruction moves owned operand to its result, ending its
719+ // lifetime. If the result is guaranteed value, then the instruction propagates
720+ // the lifetime of its borrows operand through its result.
721+ inline OperandOwnership
722+ ValueOwnershipKind::getForwardingOperandOwnership () const {
723+ switch (value) {
724+ case OwnershipKind::Any:
725+ llvm_unreachable (" invalid value ownership" );
726+ case OwnershipKind::None:
727+ return OperandOwnership::None;
728+ case OwnershipKind::Unowned:
729+ return OperandOwnership::ForwardingUnowned;
730+ case OwnershipKind::Guaranteed:
731+ return OperandOwnership::ForwardingBorrow;
732+ case OwnershipKind::Owned:
733+ return OperandOwnership::ForwardingConsume;
734+ }
735+ }
736+
621737// / A formal SIL reference to a value, suitable for use as a stored
622738// / operand.
623739class Operand {
@@ -695,12 +811,22 @@ class Operand {
695811 // / Return which operand this is in the operand list of the using instruction.
696812 unsigned getOperandNumber () const ;
697813
814+ // / Return the use ownership of this operand. Returns none if the operand is a
815+ // / type dependent operand.
816+ // /
817+ // / NOTE: This is implemented in OperandOwnership.cpp.
818+ Optional<OperandOwnership> getOperandOwnership () const ;
819+
698820 // / Return the ownership constraint that restricts what types of values this
699821 // / Operand can contain. Returns none if the operand is a type dependent
700822 // / operand.
701- // /
702- // / NOTE: This is implemented in OperandOwnership.cpp.
703- Optional<OwnershipConstraint> getOwnershipConstraint () const ;
823+ Optional<OwnershipConstraint> getOwnershipConstraint () const {
824+ auto operandOwnership = getOperandOwnership ();
825+ if (!operandOwnership) {
826+ return None;
827+ }
828+ return swift::getOwnershipConstraint (operandOwnership.getValue ());
829+ }
704830
705831 // / Returns true if changing the operand to use a value with the given
706832 // / ownership kind would not cause the operand to violate the operand's
@@ -711,24 +837,28 @@ class Operand {
711837 // / operand constraint.
712838 bool satisfiesConstraints () const ;
713839
714- // / Returns true if this operand acts as a use that consumes its associated
715- // / value.
840+ // / Returns true if this operand acts as a use that ends the lifetime its
841+ // / associated value, either by consuming the owned value or ending the
842+ // / guaranteed scope.
716843 bool isLifetimeEnding () const ;
717844
718845 SILBasicBlock *getParentBlock () const ;
719846 SILFunction *getParentFunction () const ;
720847
721848private:
722849 void removeFromCurrent () {
723- if (!Back) return ;
850+ if (!Back)
851+ return ;
724852 *Back = NextUse;
725- if (NextUse) NextUse->Back = Back;
853+ if (NextUse)
854+ NextUse->Back = Back;
726855 }
727856
728857 void insertIntoCurrent () {
729858 Back = &TheValue->FirstUse ;
730859 NextUse = TheValue->FirstUse ;
731- if (NextUse) NextUse->Back = &NextUse;
860+ if (NextUse)
861+ NextUse->Back = &NextUse;
732862 TheValue->FirstUse = this ;
733863 }
734864
0 commit comments