@@ -226,6 +226,8 @@ struct OwnershipKind {
226
226
227
227
llvm::raw_ostream &operator <<(llvm::raw_ostream &os, const OwnershipKind &kind);
228
228
229
+ enum class OperandOwnership ;
230
+
229
231
// / A value representing the specific ownership semantics that a SILValue may
230
232
// / have.
231
233
struct ValueOwnershipKind {
@@ -286,6 +288,8 @@ struct ValueOwnershipKind {
286
288
llvm_unreachable (" covered switch" );
287
289
}
288
290
291
+ OperandOwnership getForwardingOperandOwnership () const ;
292
+
289
293
// / Returns true if \p Other can be merged successfully with this, implying
290
294
// / that the two ownership kinds are "compatibile".
291
295
// /
@@ -597,12 +601,6 @@ class OwnershipConstraint {
597
601
return lifetimeConstraint;
598
602
}
599
603
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
-
606
604
bool satisfiedBy (const Operand *use) const ;
607
605
608
606
bool satisfiesConstraint (ValueOwnershipKind testKind) const {
@@ -618,6 +616,124 @@ class OwnershipConstraint {
618
616
llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
619
617
OwnershipConstraint constraint);
620
618
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
+
621
737
// / A formal SIL reference to a value, suitable for use as a stored
622
738
// / operand.
623
739
class Operand {
@@ -695,12 +811,22 @@ class Operand {
695
811
// / Return which operand this is in the operand list of the using instruction.
696
812
unsigned getOperandNumber () const ;
697
813
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
+
698
820
// / Return the ownership constraint that restricts what types of values this
699
821
// / Operand can contain. Returns none if the operand is a type dependent
700
822
// / 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
+ }
704
830
705
831
// / Returns true if changing the operand to use a value with the given
706
832
// / ownership kind would not cause the operand to violate the operand's
@@ -711,24 +837,28 @@ class Operand {
711
837
// / operand constraint.
712
838
bool satisfiesConstraints () const ;
713
839
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.
716
843
bool isLifetimeEnding () const ;
717
844
718
845
SILBasicBlock *getParentBlock () const ;
719
846
SILFunction *getParentFunction () const ;
720
847
721
848
private:
722
849
void removeFromCurrent () {
723
- if (!Back) return ;
850
+ if (!Back)
851
+ return ;
724
852
*Back = NextUse;
725
- if (NextUse) NextUse->Back = Back;
853
+ if (NextUse)
854
+ NextUse->Back = Back;
726
855
}
727
856
728
857
void insertIntoCurrent () {
729
858
Back = &TheValue->FirstUse ;
730
859
NextUse = TheValue->FirstUse ;
731
- if (NextUse) NextUse->Back = &NextUse;
860
+ if (NextUse)
861
+ NextUse->Back = &NextUse;
732
862
TheValue->FirstUse = this ;
733
863
}
734
864
0 commit comments