@@ -47,7 +47,25 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
4747
4848namespace {
4949
50- class LiveRange {
50+ // / This class represents an "extended live range" of an owned value. Such a
51+ // / representation includes:
52+ // /
53+ // / 1. The owned introducing value.
54+ // / 2. Any forwarding instructions that consume the introduced value
55+ // / (transitively) and then propagate a new owned value.
56+ // / 3. Transitive destroys on the forwarding instructions/destroys on the owned
57+ // / introducing value.
58+ // / 4. Any unknown consuming uses that are not understood by this code.
59+ // /
60+ // / This allows for this to be used to convert such a set of uses from using
61+ // / owned ownership to using guaranteed ownership by converting the
62+ // / destroy_value -> end_borrow and "flipping" the ownership of individual
63+ // / forwarding instructions.
64+ // /
65+ // / NOTE: We do not look through "phi nodes" in the ownership graph (e.x.: real
66+ // / phi arguments, struct, tuple). Instead we represent those as nodes in a
67+ // / larger phi ownership web, connected via individual OwnershipLiveRange.
68+ class OwnershipLiveRange {
5169 // / The value that we are computing the LiveRange for. Expected to be an owned
5270 // / introducer and not to be forwarding.
5371 OwnedValueIntroducer introducer;
@@ -71,9 +89,18 @@ class LiveRange {
7189 ArrayRef<Operand *> destroyingUses;
7290
7391 // / A list of forwarding instructions that forward owned ownership, but that
74- // / are also able to be converted to guaranteed ownership. If we are able to
75- // / eliminate this LiveRange due to it being from a guaranteed value, we must
76- // / flip the ownership of all of these instructions to guaranteed from owned.
92+ // / are also able to be converted to guaranteed ownership.
93+ // /
94+ // / If we are able to eliminate this LiveRange due to it being from a
95+ // / guaranteed value, we must flip the ownership of all of these instructions
96+ // / to guaranteed from owned.
97+ // /
98+ // / NOTE: Normally only destroying or consuming uses end the live range. We
99+ // / copy these transitive uses as well into the consumingUses array since
100+ // / transitive uses can extend a live range up to an unreachable block without
101+ // / ultimately being consuming. In such a situation if we did not also store
102+ // / this into consuming uses, we would not be able to ascertain just using the
103+ // / "consumingUses" array the true lifetime of the OwnershipLiveRange.
77104 // /
78105 // / Corresponds to isOwnershipForwardingInst(...).
79106 ArrayRef<Operand *> ownershipForwardingUses;
@@ -84,9 +111,9 @@ class LiveRange {
84111 ArrayRef<Operand *> unknownConsumingUses;
85112
86113public:
87- LiveRange (SILValue value);
88- LiveRange (const LiveRange &) = delete ;
89- LiveRange &operator =(const LiveRange &) = delete ;
114+ OwnershipLiveRange (SILValue value);
115+ OwnershipLiveRange (const OwnershipLiveRange &) = delete ;
116+ OwnershipLiveRange &operator =(const OwnershipLiveRange &) = delete ;
90117
91118 enum class HasConsumingUse_t {
92119 No = 0 ,
@@ -194,7 +221,7 @@ class LiveRange {
194221
195222} // end anonymous namespace
196223
197- struct LiveRange ::OperandToUser {
224+ struct OwnershipLiveRange ::OperandToUser {
198225 OperandToUser () {}
199226
200227 SILInstruction *operator ()(const Operand *use) const {
@@ -203,11 +230,12 @@ struct LiveRange::OperandToUser {
203230 }
204231};
205232
206- LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts () const {
233+ OwnershipLiveRange::DestroyingInstsRange
234+ OwnershipLiveRange::getDestroyingInsts () const {
207235 return DestroyingInstsRange (getDestroyingUses (), OperandToUser ());
208236}
209237
210- LiveRange::LiveRange (SILValue value)
238+ OwnershipLiveRange::OwnershipLiveRange (SILValue value)
211239 : introducer(*OwnedValueIntroducer::get (value)), destroyingUses(),
212240 ownershipForwardingUses(), unknownConsumingUses() {
213241 assert (introducer.value .getOwnershipKind () == ValueOwnershipKind::Owned);
@@ -324,7 +352,7 @@ LiveRange::LiveRange(SILValue value)
324352 unknownConsumingUses = cUseArrayRef.take_back (tmpUnknownConsumingUses.size ());
325353}
326354
327- void LiveRange ::insertEndBorrowsAtDestroys (
355+ void OwnershipLiveRange ::insertEndBorrowsAtDestroys (
328356 SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks,
329357 ValueLifetimeAnalysis::Frontier &scratch) {
330358 assert (scratch.empty () && " Expected scratch to be initially empty?!" );
@@ -377,7 +405,7 @@ void LiveRange::insertEndBorrowsAtDestroys(
377405 }
378406}
379407
380- void LiveRange ::convertOwnedGeneralForwardingUsesToGuaranteed () && {
408+ void OwnershipLiveRange ::convertOwnedGeneralForwardingUsesToGuaranteed () && {
381409 while (!ownershipForwardingUses.empty ()) {
382410 auto *i = ownershipForwardingUses.back ()->getUser ();
383411 ownershipForwardingUses = ownershipForwardingUses.drop_back ();
@@ -437,8 +465,8 @@ void LiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && {
437465 }
438466}
439467
440- void LiveRange ::convertToGuaranteedAndRAUW (SILValue newGuaranteedValue,
441- InstModCallbacks callbacks) && {
468+ void OwnershipLiveRange ::convertToGuaranteedAndRAUW (
469+ SILValue newGuaranteedValue, InstModCallbacks callbacks) && {
442470 auto *value = cast<SingleValueInstruction>(introducer.value );
443471 while (!destroyingUses.empty ()) {
444472 auto *d = destroyingUses.back ();
@@ -455,9 +483,9 @@ void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
455483 std::move (*this ).convertOwnedGeneralForwardingUsesToGuaranteed ();
456484}
457485
458- void LiveRange ::convertArgToGuaranteed (DeadEndBlocks &deadEndBlocks,
459- ValueLifetimeAnalysis::Frontier &scratch,
460- InstModCallbacks callbacks) && {
486+ void OwnershipLiveRange ::convertArgToGuaranteed (
487+ DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch,
488+ InstModCallbacks callbacks) && {
461489 // First convert the phi argument to be guaranteed.
462490 auto *phiArg = cast<SILPhiArgument>(introducer.value );
463491 phiArg->setOwnershipKind (ValueOwnershipKind::Guaranteed);
@@ -481,8 +509,8 @@ void LiveRange::convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks,
481509 std::move (*this ).convertOwnedGeneralForwardingUsesToGuaranteed ();
482510}
483511
484- LiveRange ::HasConsumingUse_t
485- LiveRange ::hasUnknownConsumingUse (bool assumingAtFixPoint) const {
512+ OwnershipLiveRange ::HasConsumingUse_t
513+ OwnershipLiveRange ::hasUnknownConsumingUse (bool assumingAtFixPoint) const {
486514 // First do a quick check if we have /any/ unknown consuming
487515 // uses. If we do not have any, return false early.
488516 if (unknownConsumingUses.empty ()) {
@@ -853,7 +881,7 @@ struct SemanticARCOptVisitor
853881 FORWARDING_TERM (Branch)
854882#undef FORWARDING_TERM
855883
856- bool isWrittenTo (LoadInst *li, const LiveRange &lr);
884+ bool isWrittenTo (LoadInst *li, const OwnershipLiveRange &lr);
857885
858886 bool processWorklist ();
859887 bool optimize ();
@@ -963,7 +991,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() {
963991 // only handle cases now where the result does not have any additional
964992 // ownershipPhi uses.
965993 SILValue joinedIntroducer = pair.first ;
966- LiveRange joinedLiveRange (joinedIntroducer);
994+ OwnershipLiveRange joinedLiveRange (joinedIntroducer);
967995 if (bool (joinedLiveRange.hasUnknownConsumingUse ())) {
968996 continue ;
969997 }
@@ -1014,7 +1042,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() {
10141042 SmallVector<std::pair<SILValue, unsigned >, 8 > incomingValueUpdates;
10151043 for (auto introducer : ownedValueIntroducers) {
10161044 SILValue v = introducer.value ;
1017- LiveRange lr (v);
1045+ OwnershipLiveRange lr (v);
10181046
10191047 // For now, we only handle copy_value for simplicity.
10201048 //
@@ -1267,10 +1295,11 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
12671295 // be some consuming use that we either do not understand is /actually/
12681296 // forwarding or a user that truly represents a necessary consume of the value
12691297 // (e.x. storing into memory).
1270- LiveRange lr (cvi);
1298+ OwnershipLiveRange lr (cvi);
12711299 auto hasUnknownConsumingUseState =
12721300 lr.hasUnknownConsumingUse (assumingAtFixedPoint);
1273- if (hasUnknownConsumingUseState == LiveRange::HasConsumingUse_t::Yes) {
1301+ if (hasUnknownConsumingUseState ==
1302+ OwnershipLiveRange::HasConsumingUse_t::Yes) {
12741303 return false ;
12751304 }
12761305
@@ -1377,7 +1406,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
13771406 // we need to handle the phi arg uses, we bail. After we reach a fixed point,
13781407 // we will try to eliminate this value then.
13791408 if (hasUnknownConsumingUseState ==
1380- LiveRange ::HasConsumingUse_t::YesButAllPhiArgs) {
1409+ OwnershipLiveRange ::HasConsumingUse_t::YesButAllPhiArgs) {
13811410 auto *op = lr.getSingleUnknownConsumingUse ();
13821411 assert (op);
13831412 unsigned opNum = op->getOperandNumber ();
@@ -1392,7 +1421,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
13921421 };
13931422
13941423 auto *arg = succBlock->getSILPhiArguments ()[opNum];
1395- LiveRange phiArgLR (arg);
1424+ OwnershipLiveRange phiArgLR (arg);
13961425 if (bool (phiArgLR.hasUnknownConsumingUse ())) {
13971426 return false ;
13981427 }
@@ -1663,7 +1692,7 @@ class StorageGuaranteesLoadVisitor
16631692 SemanticARCOptVisitor &ARCOpt;
16641693
16651694 // The live range of the original load.
1666- const LiveRange &liveRange;
1695+ const OwnershipLiveRange &liveRange;
16671696
16681697 // The current address being visited.
16691698 SILValue currentAddress;
@@ -1672,7 +1701,7 @@ class StorageGuaranteesLoadVisitor
16721701
16731702public:
16741703 StorageGuaranteesLoadVisitor (SemanticARCOptVisitor &arcOpt, LoadInst *load,
1675- const LiveRange &liveRange)
1704+ const OwnershipLiveRange &liveRange)
16761705 : ARCOpt(arcOpt), liveRange(liveRange),
16771706 currentAddress (load->getOperand ()) {}
16781707
@@ -1920,7 +1949,8 @@ class StorageGuaranteesLoadVisitor
19201949
19211950} // namespace
19221951
1923- bool SemanticARCOptVisitor::isWrittenTo (LoadInst *load, const LiveRange &lr) {
1952+ bool SemanticARCOptVisitor::isWrittenTo (LoadInst *load,
1953+ const OwnershipLiveRange &lr) {
19241954 StorageGuaranteesLoadVisitor visitor (*this , load, lr);
19251955 return visitor.doIt ();
19261956}
@@ -1938,7 +1968,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
19381968 // FIXME: We should consider if it is worth promoting a load [copy]
19391969 // -> load_borrow if we can put a copy_value on a cold path and thus
19401970 // eliminate RR traffic on a hot path.
1941- LiveRange lr (li);
1971+ OwnershipLiveRange lr (li);
19421972 if (bool (lr.hasUnknownConsumingUse ()))
19431973 return false ;
19441974
0 commit comments