Skip to content

Commit 9ab0427

Browse files
committed
[ownership] Add a new construct: OwnedValueIntroducer for dealing with non-forwarding owned values at a higher level.
This is a similar concept to "rc-identity" that we talk about in the low level ARC optimizer. The main idea is that all owned values in a program can be partitioned into two different kinds of values: 1. Introducer values that exist independently of any other local values in the function. It is a point of truth from which the owned objects lifetime extends from and is in a certain sense an initialization (in a category theoretic sense) in the lifetime of the underlying object that we are manipulating. 2. Forwarding values do not represent an object lifetime that is "truly" independent of any other value locally: its liveness comes from passing on liveness from some introducer or some other forwarding value. The reason why I am adding this new construct is that I am beginning to implement a new form of ARC optimization that enables us to convert @owned SIL phi arguments to @guaranteed phi arguments. As part of that, I need to have a way to in a systematic way finding the underlying incoming values (using the logic used to determine forwarding in the ownership verifier). This is the first part of that effort, defining the ontology we are going to work with. Keep in mind this is just a seed ontology, if I missed any "owned introducers" (I am sure I did), feel free to add them.
1 parent c825ed8 commit 9ab0427

File tree

1 file changed

+147
-7
lines changed

1 file changed

+147
-7
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 147 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
371371
bool getAllBorrowIntroducingValues(
372372
SILValue value, SmallVectorImpl<BorrowScopeIntroducingValue> &out);
373373

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-
381374
/// Look up through the def-use chain of \p inputValue, looking for an initial
382375
/// "borrow" introducing value. If at any point, we find two introducers or we
383376
/// find a point in the chain we do not understand, we bail and return false. If
@@ -467,6 +460,153 @@ struct InteriorPointerOperand {
467460
: operand(op), kind(kind) {}
468461
};
469462

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

472612
#endif

0 commit comments

Comments
 (0)