@@ -47,7 +47,25 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
47
47
48
48
namespace {
49
49
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 {
51
69
// / The value that we are computing the LiveRange for. Expected to be an owned
52
70
// / introducer and not to be forwarding.
53
71
OwnedValueIntroducer introducer;
@@ -71,9 +89,18 @@ class LiveRange {
71
89
ArrayRef<Operand *> destroyingUses;
72
90
73
91
// / 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.
77
104
// /
78
105
// / Corresponds to isOwnershipForwardingInst(...).
79
106
ArrayRef<Operand *> ownershipForwardingUses;
@@ -84,9 +111,9 @@ class LiveRange {
84
111
ArrayRef<Operand *> unknownConsumingUses;
85
112
86
113
public:
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 ;
90
117
91
118
enum class HasConsumingUse_t {
92
119
No = 0 ,
@@ -194,7 +221,7 @@ class LiveRange {
194
221
195
222
} // end anonymous namespace
196
223
197
- struct LiveRange ::OperandToUser {
224
+ struct OwnershipLiveRange ::OperandToUser {
198
225
OperandToUser () {}
199
226
200
227
SILInstruction *operator ()(const Operand *use) const {
@@ -203,11 +230,12 @@ struct LiveRange::OperandToUser {
203
230
}
204
231
};
205
232
206
- LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts () const {
233
+ OwnershipLiveRange::DestroyingInstsRange
234
+ OwnershipLiveRange::getDestroyingInsts () const {
207
235
return DestroyingInstsRange (getDestroyingUses (), OperandToUser ());
208
236
}
209
237
210
- LiveRange::LiveRange (SILValue value)
238
+ OwnershipLiveRange::OwnershipLiveRange (SILValue value)
211
239
: introducer(*OwnedValueIntroducer::get (value)), destroyingUses(),
212
240
ownershipForwardingUses(), unknownConsumingUses() {
213
241
assert (introducer.value .getOwnershipKind () == ValueOwnershipKind::Owned);
@@ -324,7 +352,7 @@ LiveRange::LiveRange(SILValue value)
324
352
unknownConsumingUses = cUseArrayRef.take_back (tmpUnknownConsumingUses.size ());
325
353
}
326
354
327
- void LiveRange ::insertEndBorrowsAtDestroys (
355
+ void OwnershipLiveRange ::insertEndBorrowsAtDestroys (
328
356
SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks,
329
357
ValueLifetimeAnalysis::Frontier &scratch) {
330
358
assert (scratch.empty () && " Expected scratch to be initially empty?!" );
@@ -377,7 +405,7 @@ void LiveRange::insertEndBorrowsAtDestroys(
377
405
}
378
406
}
379
407
380
- void LiveRange ::convertOwnedGeneralForwardingUsesToGuaranteed () && {
408
+ void OwnershipLiveRange ::convertOwnedGeneralForwardingUsesToGuaranteed () && {
381
409
while (!ownershipForwardingUses.empty ()) {
382
410
auto *i = ownershipForwardingUses.back ()->getUser ();
383
411
ownershipForwardingUses = ownershipForwardingUses.drop_back ();
@@ -437,8 +465,8 @@ void LiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && {
437
465
}
438
466
}
439
467
440
- void LiveRange ::convertToGuaranteedAndRAUW (SILValue newGuaranteedValue,
441
- InstModCallbacks callbacks) && {
468
+ void OwnershipLiveRange ::convertToGuaranteedAndRAUW (
469
+ SILValue newGuaranteedValue, InstModCallbacks callbacks) && {
442
470
auto *value = cast<SingleValueInstruction>(introducer.value );
443
471
while (!destroyingUses.empty ()) {
444
472
auto *d = destroyingUses.back ();
@@ -455,9 +483,9 @@ void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
455
483
std::move (*this ).convertOwnedGeneralForwardingUsesToGuaranteed ();
456
484
}
457
485
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) && {
461
489
// First convert the phi argument to be guaranteed.
462
490
auto *phiArg = cast<SILPhiArgument>(introducer.value );
463
491
phiArg->setOwnershipKind (ValueOwnershipKind::Guaranteed);
@@ -481,8 +509,8 @@ void LiveRange::convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks,
481
509
std::move (*this ).convertOwnedGeneralForwardingUsesToGuaranteed ();
482
510
}
483
511
484
- LiveRange ::HasConsumingUse_t
485
- LiveRange ::hasUnknownConsumingUse (bool assumingAtFixPoint) const {
512
+ OwnershipLiveRange ::HasConsumingUse_t
513
+ OwnershipLiveRange ::hasUnknownConsumingUse (bool assumingAtFixPoint) const {
486
514
// First do a quick check if we have /any/ unknown consuming
487
515
// uses. If we do not have any, return false early.
488
516
if (unknownConsumingUses.empty ()) {
@@ -853,7 +881,7 @@ struct SemanticARCOptVisitor
853
881
FORWARDING_TERM (Branch)
854
882
#undef FORWARDING_TERM
855
883
856
- bool isWrittenTo (LoadInst *li, const LiveRange &lr);
884
+ bool isWrittenTo (LoadInst *li, const OwnershipLiveRange &lr);
857
885
858
886
bool processWorklist ();
859
887
bool optimize ();
@@ -963,7 +991,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() {
963
991
// only handle cases now where the result does not have any additional
964
992
// ownershipPhi uses.
965
993
SILValue joinedIntroducer = pair.first ;
966
- LiveRange joinedLiveRange (joinedIntroducer);
994
+ OwnershipLiveRange joinedLiveRange (joinedIntroducer);
967
995
if (bool (joinedLiveRange.hasUnknownConsumingUse ())) {
968
996
continue ;
969
997
}
@@ -1014,7 +1042,7 @@ bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() {
1014
1042
SmallVector<std::pair<SILValue, unsigned >, 8 > incomingValueUpdates;
1015
1043
for (auto introducer : ownedValueIntroducers) {
1016
1044
SILValue v = introducer.value ;
1017
- LiveRange lr (v);
1045
+ OwnershipLiveRange lr (v);
1018
1046
1019
1047
// For now, we only handle copy_value for simplicity.
1020
1048
//
@@ -1267,10 +1295,11 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
1267
1295
// be some consuming use that we either do not understand is /actually/
1268
1296
// forwarding or a user that truly represents a necessary consume of the value
1269
1297
// (e.x. storing into memory).
1270
- LiveRange lr (cvi);
1298
+ OwnershipLiveRange lr (cvi);
1271
1299
auto hasUnknownConsumingUseState =
1272
1300
lr.hasUnknownConsumingUse (assumingAtFixedPoint);
1273
- if (hasUnknownConsumingUseState == LiveRange::HasConsumingUse_t::Yes) {
1301
+ if (hasUnknownConsumingUseState ==
1302
+ OwnershipLiveRange::HasConsumingUse_t::Yes) {
1274
1303
return false ;
1275
1304
}
1276
1305
@@ -1377,7 +1406,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
1377
1406
// we need to handle the phi arg uses, we bail. After we reach a fixed point,
1378
1407
// we will try to eliminate this value then.
1379
1408
if (hasUnknownConsumingUseState ==
1380
- LiveRange ::HasConsumingUse_t::YesButAllPhiArgs) {
1409
+ OwnershipLiveRange ::HasConsumingUse_t::YesButAllPhiArgs) {
1381
1410
auto *op = lr.getSingleUnknownConsumingUse ();
1382
1411
assert (op);
1383
1412
unsigned opNum = op->getOperandNumber ();
@@ -1392,7 +1421,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
1392
1421
};
1393
1422
1394
1423
auto *arg = succBlock->getSILPhiArguments ()[opNum];
1395
- LiveRange phiArgLR (arg);
1424
+ OwnershipLiveRange phiArgLR (arg);
1396
1425
if (bool (phiArgLR.hasUnknownConsumingUse ())) {
1397
1426
return false ;
1398
1427
}
@@ -1663,7 +1692,7 @@ class StorageGuaranteesLoadVisitor
1663
1692
SemanticARCOptVisitor &ARCOpt;
1664
1693
1665
1694
// The live range of the original load.
1666
- const LiveRange &liveRange;
1695
+ const OwnershipLiveRange &liveRange;
1667
1696
1668
1697
// The current address being visited.
1669
1698
SILValue currentAddress;
@@ -1672,7 +1701,7 @@ class StorageGuaranteesLoadVisitor
1672
1701
1673
1702
public:
1674
1703
StorageGuaranteesLoadVisitor (SemanticARCOptVisitor &arcOpt, LoadInst *load,
1675
- const LiveRange &liveRange)
1704
+ const OwnershipLiveRange &liveRange)
1676
1705
: ARCOpt(arcOpt), liveRange(liveRange),
1677
1706
currentAddress (load->getOperand ()) {}
1678
1707
@@ -1920,7 +1949,8 @@ class StorageGuaranteesLoadVisitor
1920
1949
1921
1950
} // namespace
1922
1951
1923
- bool SemanticARCOptVisitor::isWrittenTo (LoadInst *load, const LiveRange &lr) {
1952
+ bool SemanticARCOptVisitor::isWrittenTo (LoadInst *load,
1953
+ const OwnershipLiveRange &lr) {
1924
1954
StorageGuaranteesLoadVisitor visitor (*this , load, lr);
1925
1955
return visitor.doIt ();
1926
1956
}
@@ -1938,7 +1968,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
1938
1968
// FIXME: We should consider if it is worth promoting a load [copy]
1939
1969
// -> load_borrow if we can put a copy_value on a cold path and thus
1940
1970
// eliminate RR traffic on a hot path.
1941
- LiveRange lr (li);
1971
+ OwnershipLiveRange lr (li);
1942
1972
if (bool (lr.hasUnknownConsumingUse ()))
1943
1973
return false ;
1944
1974
0 commit comments