Skip to content

Commit 660384f

Browse files
committed
[semantic-arc-opts] Perform a rename/add some comments after talking with @atrick.
This should add additional clarity to the pass's impl.
1 parent 6fa4874 commit 660384f

File tree

1 file changed

+60
-30
lines changed

1 file changed

+60
-30
lines changed

lib/SILOptimizer/Transforms/SemanticARCOpts.cpp

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,25 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
4747

4848
namespace {
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

86113
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;
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

16731702
public:
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

Comments
 (0)