@@ -116,10 +116,18 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
116
116
// / statically. Thus we treat Any as representing an invalid
117
117
// / value. ValueOwnershipKinds can only perform a meet operation to determine
118
118
// / if two ownership kinds are compatible with a merge of Any showing the
119
- // / merge is impossible since values can not have any ownership.
119
+ // / merge is impossible since values can not have any ownership. Values with
120
+ // / ownership None are statically proven to be trivial values, often because
121
+ // / they are trivially typed, but sometimes because of path-sensitive
122
+ // / information like knowledge of an enum case. Trivial values have no
123
+ // / ownership semantics.
120
124
// /
121
- // / * OperandConstraint: This represents a constraint on the values that can be
122
- // / used by a specific operand. Here Any is valid.
125
+ // / * OwnershipConstraint: This represents a constraint on the values that can
126
+ // / be used by a specific operand. Here Any is valid and is used for operands
127
+ // / that don't care about the ownership kind (lack ownership constraints). In
128
+ // / contrast, a constraint of None is the most restrictive. It requires a
129
+ // / trivial value. An Unowned, Owned, or Guaranteed constraint requires either
130
+ // / a value with the named ownership, or a trivial value.
123
131
struct OwnershipKind {
124
132
enum innerty : uint8_t {
125
133
// / An ownership kind that models an ownership that is unknown statically at
@@ -159,10 +167,12 @@ struct OwnershipKind {
159
167
Guaranteed,
160
168
161
169
// / A SILValue with None ownership kind is an independent value outside of
162
- // / the ownership system. It is used to model trivially typed values as well
170
+ // / the ownership system. It is used to model values that are statically
171
+ // / determined to be trivial. This includes trivially typed values as well
163
172
// / as trivial cases of non-trivial enums. Naturally None can be merged with
164
173
// / any ValueOwnershipKind allowing us to naturally model merge and branch
165
- // / points in the SSA graph.
174
+ // / points in the SSA graph, where more information about the value is
175
+ // / statically available on some control flow paths.
166
176
None,
167
177
168
178
LastValueOwnershipKind = None,
@@ -578,6 +588,18 @@ inline bool ValueOwnershipKind::isCompatibleWith(SILValue other) const {
578
588
return isCompatibleWith (other.getOwnershipKind ());
579
589
}
580
590
591
+ // / Constraints on the ownership of an operand value.
592
+ // /
593
+ // / The ownershipKind component constrains the operand's value ownership to be
594
+ // / the same or "above" the constraint in the lattice, such that
595
+ // / join(constraint, valueOwnership) == valueOwnership. In other words, applying
596
+ // / the constraint does not change the value's ownership. For example, a value
597
+ // / with None ownership is accepted by any OwnershipConstraint, and an
598
+ // / OwnershipConstraint with 'Any' ownership kind can accept any value. Note
599
+ // / that operands commonly allow either Owned or Guaranteed operands. These
600
+ // / operands have an Any ownership constraint to allow either. However,
601
+ // / enforcement of Unowned value is more strict. This requires separate logic in
602
+ // / canAcceptUnownedValue() to avoid complicating the OwnershipKind lattice.
581
603
class OwnershipConstraint {
582
604
OwnershipKind ownershipKind;
583
605
UseLifetimeConstraint lifetimeConstraint;
@@ -624,11 +646,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
624
646
// / Used to verify completeness of the ownership use model and exhaustively
625
647
// / switch over any category of ownership use. Implies ownership constraints and
626
648
// / lifetime constraints.
649
+ // /
650
+ // / OperandOwnership may be statically determined by the user's opcode alone, or
651
+ // / by the opcode and operand type. Or it may be dynamically determined by an
652
+ // / ownership kind variable in the user's state. However, it may never be
653
+ // / inferred from the ownership of the incoming value. This way, the logic for
654
+ // / determining which ValueOwnershipKind an operand may accept is reliable.
655
+ // /
656
+ // / Any use that takes an Owned or Guaranteed value may also take a trivial
657
+ // / value (ownership None), because the ownership semantics are irrelevant.
627
658
struct OperandOwnership {
628
659
enum innerty : uint8_t {
629
- // / Uses of ownership None. These uses are incompatible with values that
630
- // / have ownership but are otherwise not verified.
631
- None,
660
+ // / Operands that do not use the value. They only represent a dependence
661
+ // / on a dominating definition and do not require liveness.
662
+ // / (type-dependent operands)
663
+ NonUse,
664
+
665
+ // / Uses that can only handle trivial values. The operand value must have
666
+ // / None ownership. These uses require liveness but are otherwise
667
+ // / unverified.
668
+ TrivialUse,
632
669
633
670
// / Use the value only for the duration of the operation, which may have
634
671
// / side effects. Requires an owned or guaranteed value.
@@ -659,25 +696,22 @@ struct OperandOwnership {
659
696
// / (ref_to_unowned, unchecked_trivial_bitcast)
660
697
BitwiseEscape,
661
698
662
- // / MARK: Uses of Owned values:
663
-
664
- // / Borrow. Propagates the owned value within a scope, without consuming it.
699
+ // / Borrow. Propagates the owned or guaranteed value within a scope, without
700
+ // / ending its lifetime.
665
701
// / (begin_borrow, begin_apply with @guaranteed argument)
666
702
Borrow,
703
+
704
+ // / MARK: Uses of Owned (or None) values:
705
+
667
706
// / Destroying Consume. Destroys the owned value immediately.
668
707
// / (store, destroy, @owned destructure).
669
708
DestroyingConsume,
670
709
// / Forwarding Consume. Consumes the owned value indirectly via a move.
671
710
// / (br, destructure, tuple, struct, cast, switch).
672
711
ForwardingConsume,
673
712
674
- // / MARK: Uses of Guaranteed values:
713
+ // / MARK: Uses of Guaranteed (or None) values:
675
714
676
- // / Nested Borrow. Propagates the guaranteed value within a nested borrow
677
- // / scope, without ending the outer borrow scope, following stack
678
- // / discipline.
679
- // / (begin_borrow, begin_apply with @guaranteed).
680
- NestedBorrow,
681
715
// / Interior Pointer. Propagates a trivial value (e.g. address, pointer, or
682
716
// / no-escape closure) that depends on the guaranteed value within the
683
717
// / base's borrow scope. The verifier checks that all uses of the trivial
@@ -724,22 +758,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
724
758
const OperandOwnership &operandOwnership);
725
759
726
760
// / Defined inline so the switch is eliminated for constant OperandOwnership.
761
+ // /
762
+ // / Here, an Any ownership constraint is used to allow either Owned or
763
+ // / Guaranteed values. However, enforcement of Unowned values is more
764
+ // / strict. This is handled by separate logic in canAcceptUnownedValue() to
765
+ // / avoid complicating the OwnershipKind lattice.
727
766
inline OwnershipConstraint OperandOwnership::getOwnershipConstraint () {
728
767
switch (value) {
729
- case OperandOwnership::None :
768
+ case OperandOwnership::TrivialUse :
730
769
return {OwnershipKind::None, UseLifetimeConstraint::NonLifetimeEnding};
770
+ case OperandOwnership::NonUse:
731
771
case OperandOwnership::InstantaneousUse:
732
772
case OperandOwnership::UnownedInstantaneousUse:
733
773
case OperandOwnership::ForwardingUnowned:
734
774
case OperandOwnership::PointerEscape:
735
775
case OperandOwnership::BitwiseEscape:
736
- return {OwnershipKind::Any, UseLifetimeConstraint::NonLifetimeEnding};
737
776
case OperandOwnership::Borrow:
738
- return {OwnershipKind::Owned , UseLifetimeConstraint::NonLifetimeEnding};
777
+ return {OwnershipKind::Any , UseLifetimeConstraint::NonLifetimeEnding};
739
778
case OperandOwnership::DestroyingConsume:
740
779
case OperandOwnership::ForwardingConsume:
741
780
return {OwnershipKind::Owned, UseLifetimeConstraint::LifetimeEnding};
742
- case OperandOwnership::NestedBorrow:
743
781
case OperandOwnership::InteriorPointer:
744
782
case OperandOwnership::ForwardingBorrow:
745
783
return {OwnershipKind::Guaranteed,
@@ -770,7 +808,7 @@ ValueOwnershipKind::getForwardingOperandOwnership(bool allowUnowned) const {
770
808
}
771
809
llvm_unreachable (" invalid value ownership" );
772
810
case OwnershipKind::None:
773
- return OperandOwnership::None ;
811
+ return OperandOwnership::TrivialUse ;
774
812
case OwnershipKind::Guaranteed:
775
813
return OperandOwnership::ForwardingBorrow;
776
814
case OwnershipKind::Owned:
0 commit comments