Skip to content

[ownership] Extract out SILOwnershipKind from ValueOwnershipKind into its own type and rename Invalid -> Any. #34669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/SIL/OwnershipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class BorrowedValueKind {

public:
static Optional<BorrowedValueKind> get(SILValue value) {
if (value.getOwnershipKind() != ValueOwnershipKind::Guaranteed)
if (value.getOwnershipKind() != OwnershipKind::Guaranteed)
return None;
switch (value->getKind()) {
default:
Expand Down Expand Up @@ -571,7 +571,7 @@ class OwnedValueIntroducerKind {

public:
static Optional<OwnedValueIntroducerKind> get(SILValue value) {
if (value.getOwnershipKind() != ValueOwnershipKind::Owned)
if (value.getOwnershipKind() != OwnershipKind::Owned)
return None;

switch (value->getKind()) {
Expand Down
6 changes: 3 additions & 3 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ class SILBuilder {

SILValue emitBeginBorrowOperation(SILLocation loc, SILValue v) {
if (!hasOwnership() ||
v.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Guaranteed))
v.getOwnershipKind().isCompatibleWith(OwnershipKind::Guaranteed))
return v;
return createBeginBorrow(loc, v);
}
Expand Down Expand Up @@ -2255,7 +2255,7 @@ class SILBuilder {
/// lowering for the non-address value.
void emitDestroyValueOperation(SILLocation Loc, SILValue v) {
assert(!v->getType().isAddress());
if (F->hasOwnership() && v.getOwnershipKind() == ValueOwnershipKind::None)
if (F->hasOwnership() && v.getOwnershipKind() == OwnershipKind::None)
return;
auto &lowering = getTypeLowering(v->getType());
lowering.emitDestroyValue(*this, Loc, v);
Expand All @@ -2267,7 +2267,7 @@ class SILBuilder {
SILLocation Loc, SILValue v,
Lowering::TypeLowering::TypeExpansionKind expansionKind) {
assert(!v->getType().isAddress());
if (F->hasOwnership() && v.getOwnershipKind() == ValueOwnershipKind::None)
if (F->hasOwnership() && v.getOwnershipKind() == OwnershipKind::None)
return;
auto &lowering = getTypeLowering(v->getType());
lowering.emitLoweredDestroyValue(*this, Loc, v, expansionKind);
Expand Down
4 changes: 2 additions & 2 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -2389,8 +2389,8 @@ void SILCloner<ImplClass>::visitUncheckedOwnershipConversionInst(

ValueOwnershipKind Kind = SILValue(Inst).getOwnershipKind();
if (getOpValue(Inst->getOperand()).getOwnershipKind() ==
ValueOwnershipKind::None) {
Kind = ValueOwnershipKind::None;
OwnershipKind::None) {
Kind = OwnershipKind::None;
}
recordClonedInstruction(Inst, getBuilder().createUncheckedOwnershipConversion(
getOpLocation(Inst->getLoc()),
Expand Down
19 changes: 11 additions & 8 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -879,12 +879,15 @@ class OwnershipForwardingSingleValueInst : public SingleValueInstruction {
SILDebugLocation debugLoc, SILType ty,
ValueOwnershipKind ownershipKind)
: SingleValueInstruction(kind, debugLoc, ty),
ownershipKind(ownershipKind) {}
ownershipKind(ownershipKind) {
assert(ownershipKind);
}

public:
ValueOwnershipKind getOwnershipKind() const { return ownershipKind; }
void setOwnershipKind(ValueOwnershipKind newOwnershipKind) {
ownershipKind = newOwnershipKind;
assert(ownershipKind);
}
};

Expand Down Expand Up @@ -5229,8 +5232,8 @@ class ObjectInst final : public InstructionBaseWithTrailingOperands<
unsigned NumBaseElements, bool HasOwnership)
: InstructionBaseWithTrailingOperands(
Elements, DebugLoc, Ty,
HasOwnership ? *mergeSILValueOwnership(Elements)
: ValueOwnershipKind(ValueOwnershipKind::None)) {
HasOwnership ? mergeSILValueOwnership(Elements)
: ValueOwnershipKind(OwnershipKind::None)) {
SILInstruction::Bits.ObjectInst.NumBaseElements = NumBaseElements;
}

Expand Down Expand Up @@ -5276,8 +5279,8 @@ class TupleInst final : public InstructionBaseWithTrailingOperands<
bool HasOwnership)
: InstructionBaseWithTrailingOperands(
Elems, DebugLoc, Ty,
HasOwnership ? *mergeSILValueOwnership(Elems)
: ValueOwnershipKind(ValueOwnershipKind::None)) {}
HasOwnership ? mergeSILValueOwnership(Elems)
: ValueOwnershipKind(OwnershipKind::None)) {}

/// Construct a TupleInst.
static TupleInst *create(SILDebugLocation DebugLoc, SILType Ty,
Expand Down Expand Up @@ -5353,7 +5356,7 @@ class EnumInst : public InstructionBase<SILInstructionKind::EnumInst,
EnumElementDecl *Element, SILType ResultTy)
: InstructionBase(DebugLoc, ResultTy,
Operand ? Operand.getOwnershipKind()
: ValueOwnershipKind(ValueOwnershipKind::None)),
: ValueOwnershipKind(OwnershipKind::None)),
Element(Element) {
if (Operand) {
OptionalOperand.emplace(this, Operand);
Expand Down Expand Up @@ -5645,8 +5648,8 @@ class SelectEnumInst final
: InstructionBaseWithTrailingOperands(
Operand, CaseValues, DebugLoc, Type, bool(DefaultValue), CaseCounts,
DefaultCount,
HasOwnership ? *mergeSILValueOwnership(CaseValues)
: ValueOwnershipKind(ValueOwnershipKind::None)) {
HasOwnership ? mergeSILValueOwnership(CaseValues)
: ValueOwnershipKind(OwnershipKind::None)) {
assert(CaseValues.size() - DefaultValue == CaseDecls.size());
std::uninitialized_copy(CaseDecls.begin(), CaseDecls.end(),
getTrailingObjects<EnumElementDecl *>());
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILUndef.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SILUndef : public ValueBase {
static SILUndef *getSentinelValue(SILType type, OwnerTy owner) {
// Ownership kind isn't used here, the value just needs to have a unique
// address.
return new (*owner) SILUndef(type, ValueOwnershipKind::None);
return new (*owner) SILUndef(type, OwnershipKind::None);
}

ValueOwnershipKind getOwnershipKind() const { return ownershipKind; }
Expand Down
160 changes: 125 additions & 35 deletions include/swift/SIL/SILValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,45 @@ enum class UseLifetimeConstraint {
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
UseLifetimeConstraint constraint);

/// A value representing the specific ownership semantics that a SILValue may
/// have.
struct ValueOwnershipKind {
/// A lattice that we use to classify ownership at the SIL level. None is top
/// and Any is bottom and all of the other ownership kinds are mid level nodes
/// in the lattice. Graphically the lattice looks as follows:
/// +----+
/// +-------|None|---------+
/// | +----+ |
/// | | |
/// v v v
/// +-------+ +-----+ +----------+
/// |Unowned| |Owned| |Guaranteed|
/// +-------+ +-----+ +----------+
/// | | |
/// | v |
/// | +---+ |
/// +------->|Any|<--------+
/// +---+
///
/// One moves up the lattice by performing a join operation and one moves down
/// the lattice by performing a meet operation.
///
/// This type is used in two different composition types:
///
/// * ValueOwnershipKind: This represents the ownership kind that a value can
/// take. Since our ownership system is strict, we require that all values
/// have a non-Any ownership since Any represents a type of ownership unknown
/// statically. Thus we treat Any as representing an invalid
/// value. ValueOwnershipKinds can only perform a meet operation to determine
/// if two ownership kinds are compatible with a merge of Any showing the
/// merge is impossible since values can not have any ownership.
///
/// * OperandConstraint: This represents a constraint on the values that can be
/// used by a specific operand. Here Any is valid.
struct OwnershipKind {
enum innerty : uint8_t {
/// A value used to signal that two merged ValueOwnershipKinds were
/// incompatible.
Invalid = 0,
/// An ownership kind that models an ownership that is unknown statically at
/// compile time. It is invalid when applied to values because we have
/// strict ownership rules for values. But it is an expected/normal state
/// when constraining ownership kinds.
Any = 0,

/// A SILValue with `Unowned` ownership kind is an independent value that
/// has a lifetime that is only guaranteed to last until the next program
Expand Down Expand Up @@ -134,58 +166,116 @@ struct ValueOwnershipKind {
None,

LastValueOwnershipKind = None,
} Value;
} value;

using UnderlyingType = std::underlying_type<innerty>::type;
static constexpr unsigned NumBits = SILNode::NumVOKindBits;
static constexpr UnderlyingType MaxValue = (UnderlyingType(1) << NumBits);
static constexpr uint64_t Mask = MaxValue - 1;
static_assert(unsigned(ValueOwnershipKind::LastValueOwnershipKind) < MaxValue,
static_assert(unsigned(OwnershipKind::LastValueOwnershipKind) < MaxValue,
"LastValueOwnershipKind is larger than max representable "
"ownership value?!");

ValueOwnershipKind(innerty NewValue) : Value(NewValue) {}
explicit ValueOwnershipKind(unsigned NewValue) : Value(innerty(NewValue)) {}
ValueOwnershipKind(const SILFunction &F, SILType Type,
SILArgumentConvention Convention);
OwnershipKind(OwnershipKind::innerty other) : value(other) {}
OwnershipKind(const OwnershipKind &other) : value(other.value) {}

OwnershipKind &operator=(const OwnershipKind &other) {
value = other.value;
return *this;
}

OwnershipKind &operator=(OwnershipKind::innerty other) {
value = other;
return *this;
}

operator OwnershipKind::innerty() const { return value; }

/// Move down the lattice.
OwnershipKind meet(OwnershipKind other) const {
// None merges with anything.
if (*this == OwnershipKind::None)
return other;
if (other == OwnershipKind::None)
return *this;

// At this point, if the two ownership kinds don't line up, the merge
// fails. Return any to show that we have lost information and now have a
// value kind that is invalid on values.
if (*this != other)
return OwnershipKind::Any;

// Otherwise, we are good, return *this.
return *this;
}

/// Move up the lattice.
OwnershipKind join(OwnershipKind other) const {
if (*this == OwnershipKind::Any)
return other;
if (other == OwnershipKind::Any)
return *this;
if (*this != other)
return OwnershipKind::None;
return *this;
}
};

/// A value representing the specific ownership semantics that a SILValue may
/// have.
struct ValueOwnershipKind {
using innerty = OwnershipKind::innerty;

OwnershipKind value;

ValueOwnershipKind(innerty newValue) : value(newValue) {}
ValueOwnershipKind(OwnershipKind newValue) : value(newValue) {}
explicit ValueOwnershipKind(unsigned newValue) : value(innerty(newValue)) {}
ValueOwnershipKind(const SILFunction &f, SILType type,
SILArgumentConvention convention);

/// Parse Value into a ValueOwnershipKind.
///
/// *NOTE* Emits an unreachable if an invalid value is passed in.
explicit ValueOwnershipKind(StringRef Value);
explicit ValueOwnershipKind(StringRef value);

operator OwnershipKind() const { return value; }
explicit operator unsigned() const { return value; }
operator innerty() const { return value; }

operator innerty() const { return Value; }
explicit operator bool() const { return value != OwnershipKind::Any; }

bool operator==(const swift::ValueOwnershipKind::innerty& b) {
return Value == b;
bool operator==(ValueOwnershipKind other) const {
return value == other.value;
}

/// Returns true if this ValueOwnershipKind is not invalid.
explicit operator bool() const { return Value != Invalid; }
bool operator==(innerty other) const { return value == other; }

ValueOwnershipKind merge(ValueOwnershipKind RHS) const;
/// We merge by moving down the lattice.
ValueOwnershipKind merge(ValueOwnershipKind rhs) const {
return value.meet(rhs.value);
}

/// Given that there is an aggregate value (like a struct or enum) with this
/// ownership kind, and a subobject of type Proj is being projected from the
/// aggregate, return Trivial if Proj has trivial type and the aggregate's
/// ownership kind otherwise.
ValueOwnershipKind getProjectedOwnershipKind(const SILFunction &F,
SILType Proj) const;
ValueOwnershipKind getProjectedOwnershipKind(const SILFunction &func,
SILType projType) const;

/// Return the lifetime constraint semantics for this
/// ValueOwnershipKind when forwarding ownership.
///
/// This is MustBeInvalidated for Owned and MustBeLive for all other ownership
/// kinds.
UseLifetimeConstraint getForwardingLifetimeConstraint() const {
switch (Value) {
case ValueOwnershipKind::Invalid:
llvm_unreachable("Invalid ownership doesnt have a lifetime constraint!");
case ValueOwnershipKind::None:
case ValueOwnershipKind::Guaranteed:
case ValueOwnershipKind::Unowned:
switch (value) {
case OwnershipKind::Any:
case OwnershipKind::None:
case OwnershipKind::Guaranteed:
case OwnershipKind::Unowned:
return UseLifetimeConstraint::NonLifetimeEnding;
case ValueOwnershipKind::Owned:
case OwnershipKind::Owned:
return UseLifetimeConstraint::LifetimeEnding;
}
llvm_unreachable("covered switch");
Expand All @@ -195,7 +285,7 @@ struct ValueOwnershipKind {
/// that the two ownership kinds are "compatibile".
///
/// The reason why we do not compare directy is to allow for
/// ValueOwnershipKind::None to merge into other forms of ValueOwnershipKind.
/// OwnershipKind::None to merge into other forms of ValueOwnershipKind.
bool isCompatibleWith(ValueOwnershipKind other) const {
return bool(merge(other));
}
Expand All @@ -207,7 +297,7 @@ struct ValueOwnershipKind {
bool isCompatibleWith(SILValue other) const;

template <typename RangeTy> static ValueOwnershipKind merge(RangeTy &&r) {
auto initial = ValueOwnershipKind::None;
auto initial = OwnershipKind::None;
return accumulate(std::forward<RangeTy>(r), initial,
[](ValueOwnershipKind acc, ValueOwnershipKind x) {
if (!acc)
Expand Down Expand Up @@ -495,7 +585,7 @@ struct OperandOwnershipKindMap {
// should always have a small case SmallBitVector, so there is no
// difference in size.
static constexpr unsigned NUM_DATA_BITS =
2 * (unsigned(ValueOwnershipKind::LastValueOwnershipKind) + 1);
2 * (unsigned(OwnershipKind::LastValueOwnershipKind) + 1);

/// A bit vector representing our "map". Given a ValueOwnershipKind k, if the
/// operand can accept k, the unsigned(k)*2 bit will be set to true. Assuming
Expand All @@ -512,7 +602,7 @@ struct OperandOwnershipKindMap {

/// Return the OperandOwnershipKindMap that tests for compatibility with
/// ValueOwnershipKind kind. This means that it will accept a element whose
/// ownership is ValueOwnershipKind::None.
/// ownership is OwnershipKind::None.
static OperandOwnershipKindMap
compatibilityMap(ValueOwnershipKind kind, UseLifetimeConstraint constraint) {
OperandOwnershipKindMap set;
Expand All @@ -526,7 +616,7 @@ struct OperandOwnershipKindMap {
compatibleWithAllExcept(ValueOwnershipKind kind) {
OperandOwnershipKindMap map;
unsigned index = 0;
unsigned end = unsigned(ValueOwnershipKind::LastValueOwnershipKind) + 1;
unsigned end = unsigned(OwnershipKind::LastValueOwnershipKind) + 1;
for (; index != end; ++index) {
if (ValueOwnershipKind(index) == kind) {
continue;
Expand Down Expand Up @@ -555,7 +645,7 @@ struct OperandOwnershipKindMap {
static OperandOwnershipKindMap allLive() {
OperandOwnershipKindMap map;
unsigned index = 0;
unsigned end = unsigned(ValueOwnershipKind::LastValueOwnershipKind) + 1;
unsigned end = unsigned(OwnershipKind::LastValueOwnershipKind) + 1;
while (index != end) {
map.add(ValueOwnershipKind(index),
UseLifetimeConstraint::NonLifetimeEnding);
Expand Down Expand Up @@ -584,7 +674,7 @@ struct OperandOwnershipKindMap {

void addCompatibilityConstraint(ValueOwnershipKind kind,
UseLifetimeConstraint constraint) {
add(ValueOwnershipKind::None, UseLifetimeConstraint::NonLifetimeEnding);
add(OwnershipKind::None, UseLifetimeConstraint::NonLifetimeEnding);
add(kind, constraint);
}

Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/ValueUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace swift {
///
/// NOTE: This assumes that the passed in SILValues are not values used as type
/// dependent operands.
Optional<ValueOwnershipKind> mergeSILValueOwnership(ArrayRef<SILValue> values);
ValueOwnershipKind mergeSILValueOwnership(ArrayRef<SILValue> values);

} // namespace swift

Expand Down
Loading