Skip to content

Commit 0fe0917

Browse files
authored
Merge pull request #30265 from gottesmm/pr-8d01937acb91692d7483e6a5895296634037a326
2 parents 0d361bd + 491f826 commit 0fe0917

File tree

2 files changed

+321
-7
lines changed

2 files changed

+321
-7
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 166 additions & 7 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,
@@ -371,13 +379,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
371379
bool getAllBorrowIntroducingValues(
372380
SILValue value, SmallVectorImpl<BorrowScopeIntroducingValue> &out);
373381

374-
/// Look up the def-use graph starting at \p inputOperand and see if
375-
/// we can find a single BorrowScopeIntroducingValue for \p
376-
/// inputOperand. Returns None if there are multiple such introducers
377-
/// or if while processing we find a user we do not understand.
378-
Optional<BorrowScopeIntroducingValue>
379-
getSingleBorrowIntroducingValue(SILValue value);
380-
381382
/// Look up through the def-use chain of \p inputValue, looking for an initial
382383
/// "borrow" introducing value. If at any point, we find two introducers or we
383384
/// find a point in the chain we do not understand, we bail and return false. If
@@ -467,6 +468,164 @@ struct InteriorPointerOperand {
467468
: operand(op), kind(kind) {}
468469
};
469470

471+
struct OwnedValueIntroducerKind {
472+
enum Kind {
473+
/// An owned value that is a result of an Apply.
474+
Apply,
475+
476+
/// An owned value returned as a result of applying a begin_apply.
477+
BeginApply,
478+
479+
/// An owned value that is an argument that is in one of the successor
480+
/// blocks of a try_apply. This represents in a sense the try applies
481+
/// result.
482+
TryApply,
483+
484+
/// An owned value produced as a result of performing a copy_value on some
485+
/// other value.
486+
Copy,
487+
488+
/// An owned value produced as a result of performing a load [copy] on a
489+
/// memory location.
490+
LoadCopy,
491+
492+
/// An owned value produced as a result of performing a load [take] from a
493+
/// memory location.
494+
LoadTake,
495+
496+
/// An owned value that is a result of a true phi argument.
497+
///
498+
/// A true phi argument here is defined as an SIL phi argument that only has
499+
/// branch predecessors.
500+
Phi,
501+
502+
/// An owned value that is a function argument.
503+
FunctionArgument,
504+
505+
/// An owned value that is a new partial_apply that has been formed.
506+
PartialApplyInit,
507+
508+
/// An owned value from the formation of a new alloc_box.
509+
AllocBoxInit,
510+
511+
/// An owned value from the formataion of a new alloc_ref.
512+
AllocRefInit,
513+
};
514+
515+
static Optional<OwnedValueIntroducerKind> get(SILValue value) {
516+
if (value.getOwnershipKind() != ValueOwnershipKind::Owned)
517+
return None;
518+
519+
switch (value->getKind()) {
520+
default:
521+
return None;
522+
case ValueKind::ApplyInst:
523+
return OwnedValueIntroducerKind(Apply);
524+
case ValueKind::BeginApplyResult:
525+
return OwnedValueIntroducerKind(BeginApply);
526+
case ValueKind::SILPhiArgument: {
527+
auto *phiArg = cast<SILPhiArgument>(value);
528+
if (dyn_cast_or_null<TryApplyInst>(phiArg->getSingleTerminator())) {
529+
return OwnedValueIntroducerKind(TryApply);
530+
}
531+
if (llvm::all_of(phiArg->getParent()->getPredecessorBlocks(),
532+
[](SILBasicBlock *block) {
533+
return isa<BranchInst>(block->getTerminator());
534+
})) {
535+
return OwnedValueIntroducerKind(Phi);
536+
}
537+
return None;
538+
}
539+
case ValueKind::SILFunctionArgument:
540+
return OwnedValueIntroducerKind(FunctionArgument);
541+
case ValueKind::CopyValueInst:
542+
return OwnedValueIntroducerKind(Copy);
543+
case ValueKind::LoadInst: {
544+
auto qual = cast<LoadInst>(value)->getOwnershipQualifier();
545+
if (qual == LoadOwnershipQualifier::Take)
546+
return OwnedValueIntroducerKind(LoadTake);
547+
if (qual == LoadOwnershipQualifier::Copy)
548+
return OwnedValueIntroducerKind(LoadCopy);
549+
return None;
550+
}
551+
case ValueKind::PartialApplyInst:
552+
return OwnedValueIntroducerKind(PartialApplyInit);
553+
case ValueKind::AllocBoxInst:
554+
return OwnedValueIntroducerKind(AllocBoxInit);
555+
case ValueKind::AllocRefInst:
556+
return OwnedValueIntroducerKind(AllocRefInit);
557+
}
558+
llvm_unreachable("Default should have caught this");
559+
}
560+
561+
Kind value;
562+
563+
OwnedValueIntroducerKind(Kind newValue) : value(newValue) {}
564+
OwnedValueIntroducerKind(const OwnedValueIntroducerKind &other)
565+
: value(other.value) {}
566+
operator Kind() const { return value; }
567+
568+
void print(llvm::raw_ostream &os) const;
569+
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
570+
};
571+
572+
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
573+
OwnedValueIntroducerKind kind);
574+
575+
/// A higher level construct for working with values that introduce a new
576+
/// "owned" value.
577+
///
578+
/// An owned "introducer" is a value that signals in a SIL program the begin of
579+
/// a new semantic @owned ownership construct that is live without respect to
580+
/// any other values in the function. This introducer value is then either used
581+
/// directly, forwarded then used, and then finally destroyed.
582+
///
583+
/// NOTE: Previous incarnations of this concept used terms like "RC-identity".
584+
struct OwnedValueIntroducer {
585+
/// The actual underlying value that introduces the new owned value.
586+
SILValue value;
587+
588+
/// The kind of "introducer" that we use to classify any of various possible
589+
/// underlying introducing values.
590+
OwnedValueIntroducerKind kind;
591+
592+
/// If a value is an owned value introducer we can recognize, return
593+
/// .some(OwnedValueIntroducer). Otherwise, return None.
594+
static Optional<OwnedValueIntroducer> get(SILValue value) {
595+
auto kind = OwnedValueIntroducerKind::get(value);
596+
if (!kind)
597+
return None;
598+
return OwnedValueIntroducer(value, *kind);
599+
}
600+
601+
bool operator==(const OwnedValueIntroducer &other) const {
602+
return value == other.value;
603+
}
604+
605+
bool operator!=(const OwnedValueIntroducer &other) const {
606+
return !(*this == other);
607+
}
608+
609+
bool operator<(const OwnedValueIntroducer &other) const {
610+
return value < other.value;
611+
}
612+
613+
private:
614+
OwnedValueIntroducer(SILValue value, OwnedValueIntroducerKind kind)
615+
: value(value), kind(kind) {}
616+
};
617+
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+
470629
} // namespace swift
471630

472631
#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)