Skip to content

Commit 491f826

Browse files
committed
[ownership] Implement getSingleOwnedValueIntroducer and getAllOwnedValueIntroducers().
These enable robust walking up the def-use ossa graph to find the value that introduces an independent underlying owned value, looking through forwarding insts.
1 parent 9ab0427 commit 491f826

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ bool isOwnedForwardingValueKind(SILNodeKind kind);
5858
/// forward guaranteed ownership.
5959
bool isOwnedForwardingInstruction(SILInstruction *inst);
6060

61+
/// Does this value 'forward' owned ownership, but may not be able to forward
62+
/// guaranteed ownership.
63+
///
64+
/// This will be either a multiple value instruction resuilt, a single value
65+
/// instruction that forwards or an argument that forwards the ownership from a
66+
/// previous terminator.
67+
bool isOwnedForwardingValue(SILValue value);
68+
6169
struct BorrowScopeOperandKind {
6270
enum Kind {
6371
BeginBorrow,
@@ -607,6 +615,17 @@ struct OwnedValueIntroducer {
607615
: value(value), kind(kind) {}
608616
};
609617

618+
/// Look up the def-use graph starting at use \p inputOperand, recording any
619+
/// values that act as "owned" introducers.
620+
///
621+
/// NOTE: This may return multiple owned introducers in cases where there are
622+
/// phi-like nodes in the IR like any true phi block arguments or aggregate
623+
/// literal instructions (struct, tuple, enum, etc.).
624+
bool getAllOwnedValueIntroducers(SILValue value,
625+
SmallVectorImpl<OwnedValueIntroducer> &out);
626+
627+
Optional<OwnedValueIntroducer> getSingleOwnedValueIntroducer(SILValue value);
628+
610629
} // namespace swift
611630

612631
#endif

lib/SIL/OwnershipUtils.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,17 @@ bool swift::isOwnedForwardingInstruction(SILInstruction *inst) {
8585
}
8686
}
8787

88+
bool swift::isOwnedForwardingValue(SILValue value) {
89+
switch (value->getKind()) {
90+
// Phi arguments always forward ownership.
91+
case ValueKind::SILPhiArgument:
92+
return true;
93+
default:
94+
return isOwnedForwardingValueKind(
95+
value->getKindOfRepresentativeSILNodeInObject());
96+
}
97+
}
98+
8899
bool swift::isGuaranteedForwardingValue(SILValue value) {
89100
// If we have an argument from a transforming terminator, we can forward
90101
// guaranteed.
@@ -95,6 +106,7 @@ bool swift::isGuaranteedForwardingValue(SILValue value) {
95106
}
96107
}
97108
}
109+
98110
return isGuaranteedForwardingValueKind(
99111
value->getKindOfRepresentativeSILNodeInObject());
100112
}
@@ -443,6 +455,49 @@ bool BorrowScopeIntroducingValue::visitInteriorPointerOperands(
443455
return true;
444456
}
445457

458+
//===----------------------------------------------------------------------===//
459+
// Owned Value Introducers
460+
//===----------------------------------------------------------------------===//
461+
462+
void OwnedValueIntroducerKind::print(llvm::raw_ostream &os) const {
463+
switch (value) {
464+
case OwnedValueIntroducerKind::Apply:
465+
os << "Apply";
466+
return;
467+
case OwnedValueIntroducerKind::BeginApply:
468+
os << "BeginApply";
469+
return;
470+
case OwnedValueIntroducerKind::TryApply:
471+
os << "TryApply";
472+
return;
473+
case OwnedValueIntroducerKind::Copy:
474+
os << "Copy";
475+
return;
476+
case OwnedValueIntroducerKind::LoadCopy:
477+
os << "LoadCopy";
478+
return;
479+
case OwnedValueIntroducerKind::LoadTake:
480+
os << "LoadTake";
481+
return;
482+
case OwnedValueIntroducerKind::Phi:
483+
os << "Phi";
484+
return;
485+
case OwnedValueIntroducerKind::FunctionArgument:
486+
os << "FunctionArgument";
487+
return;
488+
case OwnedValueIntroducerKind::PartialApplyInit:
489+
os << "PartialApplyInit";
490+
return;
491+
case OwnedValueIntroducerKind::AllocBoxInit:
492+
os << "AllocBoxInit";
493+
return;
494+
case OwnedValueIntroducerKind::AllocRefInit:
495+
os << "AllocRefInit";
496+
return;
497+
}
498+
llvm_unreachable("Covered switch isn't covered");
499+
}
500+
446501
//===----------------------------------------------------------------------===//
447502
// Introducer Searching Routines
448503
//===----------------------------------------------------------------------===//
@@ -546,3 +601,103 @@ swift::getSingleBorrowIntroducingValue(SILValue inputValue) {
546601

547602
llvm_unreachable("Should never hit this");
548603
}
604+
605+
bool swift::getAllOwnedValueIntroducers(
606+
SILValue inputValue, SmallVectorImpl<OwnedValueIntroducer> &out) {
607+
if (inputValue.getOwnershipKind() != ValueOwnershipKind::Owned)
608+
return false;
609+
610+
SmallVector<SILValue, 32> worklist;
611+
worklist.emplace_back(inputValue);
612+
613+
while (!worklist.empty()) {
614+
SILValue value = worklist.pop_back_val();
615+
616+
// First check if v is an introducer. If so, stash it and continue.
617+
if (auto introducer = OwnedValueIntroducer::get(value)) {
618+
out.push_back(*introducer);
619+
continue;
620+
}
621+
622+
// If v produces .none ownership, then we can ignore it. It is important
623+
// that we put this before checking for guaranteed forwarding instructions,
624+
// since we want to ignore guaranteed forwarding instructions that in this
625+
// specific case produce a .none value.
626+
if (value.getOwnershipKind() == ValueOwnershipKind::None)
627+
continue;
628+
629+
// Otherwise if v is an ownership forwarding value, add its defining
630+
// instruction
631+
if (isOwnedForwardingValue(value)) {
632+
if (auto *i = value->getDefiningInstruction()) {
633+
llvm::copy(i->getOperandValues(true /*skip type dependent ops*/),
634+
std::back_inserter(worklist));
635+
continue;
636+
}
637+
638+
// Otherwise, we should have a block argument that is defined by a single
639+
// predecessor terminator.
640+
auto *arg = cast<SILPhiArgument>(value);
641+
auto *termInst = arg->getSingleTerminator();
642+
assert(termInst && termInst->isTransformationTerminator());
643+
assert(termInst->getNumOperands() == 1 &&
644+
"Transforming terminators should always have a single operand");
645+
worklist.push_back(termInst->getAllOperands()[0].get());
646+
continue;
647+
}
648+
649+
// Otherwise, this is an introducer we do not understand. Bail and return
650+
// false.
651+
return false;
652+
}
653+
654+
return true;
655+
}
656+
657+
Optional<OwnedValueIntroducer>
658+
swift::getSingleOwnedValueIntroducer(SILValue inputValue) {
659+
if (inputValue.getOwnershipKind() != ValueOwnershipKind::Owned)
660+
return None;
661+
662+
SILValue currentValue = inputValue;
663+
while (true) {
664+
// First check if our initial value is an introducer. If we have one, just
665+
// return it.
666+
if (auto introducer = OwnedValueIntroducer::get(currentValue)) {
667+
return introducer;
668+
}
669+
670+
// Otherwise if v is an ownership forwarding value, add its defining
671+
// instruction
672+
if (isOwnedForwardingValue(currentValue)) {
673+
if (auto *i = currentValue->getDefiningInstruction()) {
674+
auto instOps = i->getOperandValues(true /*ignore type dependent ops*/);
675+
// If we have multiple incoming values, return .None. We can't handle
676+
// this.
677+
auto begin = instOps.begin();
678+
if (std::next(begin) != instOps.end()) {
679+
return None;
680+
}
681+
// Otherwise, set currentOp to the single operand and continue.
682+
currentValue = *begin;
683+
continue;
684+
}
685+
686+
// Otherwise, we should have a block argument that is defined by a single
687+
// predecessor terminator.
688+
auto *arg = cast<SILPhiArgument>(currentValue);
689+
auto *termInst = arg->getSingleTerminator();
690+
assert(termInst && termInst->isTransformationTerminator());
691+
assert(termInst->getNumOperands() == 1 &&
692+
"Transformation terminators should only have single operands");
693+
currentValue = termInst->getAllOperands()[0].get();
694+
continue;
695+
}
696+
697+
// Otherwise, this is an introducer we do not understand. Bail and return
698+
// None.
699+
return None;
700+
}
701+
702+
llvm_unreachable("Should never hit this");
703+
}

0 commit comments

Comments
 (0)