Skip to content

[4.2] Perform value operations opaquely on ABI-inaccessible types #16642

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 3 commits into from
May 16, 2018
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
6 changes: 6 additions & 0 deletions include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,12 @@ class CanType : public Type {
});
}

bool findIf(llvm::function_ref<bool (CanType)> fn) const {
return Type::findIf([&fn](Type t) {
return fn(CanType(t));
});
}

// Provide a few optimized accessors that are really type-class queries.

/// Do values of this type have reference semantics?
Expand Down
8 changes: 8 additions & 0 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,14 @@ class SILModule {
PGOReader = std::move(IPR);
}

/// Can value operations (copies and destroys) on the given lowered type
/// be performed in this module?
bool isTypeABIAccessible(SILType type);

/// Can type metadata for the given formal type be fetched in
/// the given module?
bool isTypeMetadataAccessible(CanType type);

/// \brief Run the SIL verifier to make sure that all Functions follow
/// invariants.
void verify() const;
Expand Down
136 changes: 116 additions & 20 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,35 +96,120 @@ enum IsDependent_t : unsigned {
IsNotDependent = false,
IsDependent = true
};


/// Is a lowered SIL type trivial? That is, are copies ultimately just
/// bit-copies, and it takes no work to destroy a value?
enum IsTrivial_t : bool {
IsNotTrivial = false,
IsTrivial = true
};

/// Is a lowered SIL type fixed-ABI? That is, can the current context
/// assign it a fixed size and alignment and perform value operations on it
/// (such as copies, destroys, constructions, and projections) without
/// metadata?
///
/// Note that a fully concrete type can be non-fixed-ABI without being
/// itself resilient if it contains a subobject which is not fixed-ABI.
///
/// Also note that we're only concerned with the external value ABI here:
/// resilient class types are still fixed-ABI, indirect enum cases do not
/// affect the fixed-ABI-ness of the enum, and so on.
enum IsFixedABI_t : bool {
IsNotFixedABI = false,
IsFixedABI = true
};

/// Is a lowered SIL type address-only? That is, is the current context
/// required to keep the value in memory for some reason?
///
/// A type might be address-only because:
///
/// - it is not fixed-size (e.g. because it is a resilient type) and
/// therefore cannot be loaded into a statically-boundable set of
/// registers; or
///
/// - it is semantically bound to memory, either because its storage
/// address is used by the language runtime to implement its semantics
/// (as with a weak reference) or because its representation is somehow
/// address-dependent (as with something like a relative pointer).
///
/// An address-only type can be fixed-layout and/or trivial.
/// A non-fixed-layout type is always address-only.
enum IsAddressOnly_t : bool {
IsNotAddressOnly = false,
IsAddressOnly = true
};

/// Is this type somewhat like a reference-counted type?
enum IsReferenceCounted_t : bool {
IsNotReferenceCounted = false,
IsReferenceCounted = true
};

/// Extended type information used by SIL.
class TypeLowering {
public:
enum IsTrivial_t : bool { IsNotTrivial, IsTrivial };
enum IsAddressOnly_t : bool { IsNotAddressOnly, IsAddressOnly };
enum IsReferenceCounted_t : bool {
IsNotReferenceCounted,
IsReferenceCounted
class RecursiveProperties {
// These are chosen so that bitwise-or merges the flags properly.
enum : unsigned {
NonTrivialFlag = 1 << 0,
NonFixedABIFlag = 1 << 1,
AddressOnlyFlag = 1 << 2,
};

uint8_t Flags;
public:
/// Construct a default RecursiveProperties, which corresponds to
/// a trivial, loadable, fixed-layout type.
constexpr RecursiveProperties() : Flags(0) {}

constexpr RecursiveProperties(IsTrivial_t isTrivial,
IsFixedABI_t isFixedABI,
IsAddressOnly_t isAddressOnly)
: Flags((isTrivial ? 0U : NonTrivialFlag) |
(isAddressOnly ? AddressOnlyFlag : 0U) |
(isFixedABI ? 0U : NonFixedABIFlag)) {}

static constexpr RecursiveProperties forReference() {
return {IsNotTrivial, IsFixedABI, IsNotAddressOnly};
}

static constexpr RecursiveProperties forOpaque() {
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly};
}

void addSubobject(RecursiveProperties other) {
Flags |= other.Flags;
}

IsTrivial_t isTrivial() const {
return IsTrivial_t((Flags & NonTrivialFlag) == 0);
}
IsFixedABI_t isFixedABI() const {
return IsFixedABI_t((Flags & NonFixedABIFlag) == 0);
}
IsAddressOnly_t isAddressOnly() const {
return IsAddressOnly_t((Flags & AddressOnlyFlag) != 0);
}

void setNonTrivial() { Flags |= NonTrivialFlag; }
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
void setAddressOnly() { Flags |= AddressOnlyFlag; }
};

private:
/// The SIL type of values with this Swift type.
SILType LoweredType;

enum : unsigned {
IsTrivialFlag = 0x1,
IsAddressOnlyFlag = 0x2,
IsReferenceCountedFlag = 0x4,
};
unsigned Flags;
RecursiveProperties Properties;
unsigned ReferenceCounted : 1;

protected:
TypeLowering(SILType type, IsTrivial_t isTrivial,
IsAddressOnly_t isAddressOnly,
TypeLowering(SILType type, RecursiveProperties properties,
IsReferenceCounted_t isRefCounted)
: LoweredType(type), Flags((isTrivial ? IsTrivialFlag : 0U) |
(isAddressOnly ? IsAddressOnlyFlag : 0U) |
(isRefCounted ? IsReferenceCountedFlag : 0U)) {}
: LoweredType(type), Properties(properties),
ReferenceCounted(isRefCounted) {}

public:
TypeLowering(const TypeLowering &) = delete;
Expand All @@ -143,30 +228,41 @@ class TypeLowering {
/// This is independent of whether the SIL result is address type.
bool isFormallyReturnedIndirectly() const { return isAddressOnly(); }

RecursiveProperties getRecursiveProperties() const {
return Properties;
}

/// isAddressOnly - Returns true if the type is an address-only type. A type
/// is address-only if it is a resilient value type, or if it is a fragile
/// value type with a resilient member. In either case, the full layout of
/// values of the type is unavailable to the compiler.
bool isAddressOnly() const {
return Flags & IsAddressOnlyFlag;
return Properties.isAddressOnly();
}
/// isLoadable - Returns true if the type is loadable, in other words, its
/// full layout is available to the compiler. This is the inverse of
/// isAddressOnly.
bool isLoadable() const {
return !isAddressOnly();
}

/// isFixedABI - Returns true if the type has a known fixed layout.
/// If this is true, value operations on the type can be performed even if
/// the type is inaccessible.
bool isFixedABI() const {
return Properties.isFixedABI();
}

/// Returns true if the type is trivial, meaning it is a loadable
/// value type with no reference type members that require releasing.
bool isTrivial() const {
return Flags & IsTrivialFlag;
return Properties.isTrivial();
}

/// Returns true if the type is a scalar reference-counted reference, which
/// can be retained and released.
bool isReferenceCounted() const {
return Flags & IsReferenceCountedFlag;
return ReferenceCounted;
}

/// getLoweredType - Get the type used to represent values of the Swift type
Expand Down
6 changes: 3 additions & 3 deletions lib/IRGen/FixedTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ class FixedTypeInfo : public TypeInfo {
Alignment align, IsPOD_t pod, IsBitwiseTakable_t bt,
IsFixedSize_t alwaysFixedSize,
SpecialTypeInfoKind stik = STIK_Fixed)
: TypeInfo(type, align, pod, bt, alwaysFixedSize, stik),
StorageSize(size), SpareBits(spareBits) {
: TypeInfo(type, align, pod, bt, alwaysFixedSize, IsABIAccessible, stik), StorageSize(size), SpareBits(spareBits) {
assert(SpareBits.size() == size.getValueInBits());
assert(isFixedSize());
}
Expand All @@ -61,7 +60,7 @@ class FixedTypeInfo : public TypeInfo {
Alignment align, IsPOD_t pod, IsBitwiseTakable_t bt,
IsFixedSize_t alwaysFixedSize,
SpecialTypeInfoKind stik = STIK_Fixed)
: TypeInfo(type, align, pod, bt, alwaysFixedSize, stik),
: TypeInfo(type, align, pod, bt, alwaysFixedSize, IsABIAccessible, stik),
StorageSize(size), SpareBits(std::move(spareBits)) {
assert(SpareBits.size() == size.getValueInBits());
assert(isFixedSize());
Expand All @@ -70,6 +69,7 @@ class FixedTypeInfo : public TypeInfo {
public:
// This is useful for metaprogramming.
static bool isFixed() { return true; }
static IsABIAccessible_t isABIAccessible() { return IsABIAccessible; }

/// Whether this type is known to be empty.
bool isKnownEmpty(ResilienceExpansion expansion) const {
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenArchetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ namespace {
class OpaqueArchetypeTypeInfo
: public ResilientTypeInfo<OpaqueArchetypeTypeInfo>
{
OpaqueArchetypeTypeInfo(llvm::Type *type) : ResilientTypeInfo(type) {}
OpaqueArchetypeTypeInfo(llvm::Type *type)
: ResilientTypeInfo(type, IsABIAccessible) {}

public:
static const OpaqueArchetypeTypeInfo *create(llvm::Type *type) {
Expand Down
Loading