Merge pull request #16642 from rjmccall/abi-accessibility-4.2
[4.2] Perform value operations opaquely on ABI-inaccessible types
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index 349b583..c132bd5 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -419,6 +419,12 @@
});
}
+ 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?
diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h
index 66251e7..db50b9e 100644
--- a/include/swift/SIL/SILModule.h
+++ b/include/swift/SIL/SILModule.h
@@ -634,6 +634,14 @@
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;
diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h
index 26990c6..22b9626 100644
--- a/include/swift/SIL/TypeLowering.h
+++ b/include/swift/SIL/TypeLowering.h
@@ -96,35 +96,120 @@
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;
@@ -143,12 +228,16 @@
/// 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
@@ -156,17 +245,24 @@
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
diff --git a/lib/IRGen/FixedTypeInfo.h b/lib/IRGen/FixedTypeInfo.h
index 9cabc7f..9f13336 100644
--- a/lib/IRGen/FixedTypeInfo.h
+++ b/lib/IRGen/FixedTypeInfo.h
@@ -50,8 +50,7 @@
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());
}
@@ -61,7 +60,7 @@
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());
@@ -70,6 +69,7 @@
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 {
diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp
index f99a067..27f50f8 100644
--- a/lib/IRGen/GenArchetype.cpp
+++ b/lib/IRGen/GenArchetype.cpp
@@ -89,7 +89,8 @@
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) {
diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp
index 6fb4ce1..1e98bb6 100644
--- a/lib/IRGen/GenEnum.cpp
+++ b/lib/IRGen/GenEnum.cpp
@@ -142,7 +142,8 @@
return IGM.getSize(Size(uintptr_t(flags)));
}
-SpareBitVector getBitVectorFromAPInt(const APInt &bits, unsigned startBit = 0) {
+static SpareBitVector
+getBitVectorFromAPInt(const APInt &bits, unsigned startBit = 0) {
if (startBit == 0) {
return SpareBitVector::fromAPInt(bits);
}
@@ -152,6 +153,28 @@
return result;
}
+static IsABIAccessible_t
+areElementsABIAccessible(ArrayRef<EnumImplStrategy::Element> elts) {
+ for (auto &elt : elts) {
+ if (!elt.ti->isABIAccessible())
+ return IsNotABIAccessible;
+ }
+ return IsABIAccessible;
+}
+
+EnumImplStrategy::EnumImplStrategy(IRGenModule &IGM,
+ TypeInfoKind tik,
+ IsFixedSize_t alwaysFixedSize,
+ unsigned NumElements,
+ std::vector<Element> &&eltsWithPayload,
+ std::vector<Element> &&eltsWithNoPayload)
+ : ElementsWithPayload(std::move(eltsWithPayload)),
+ ElementsWithNoPayload(std::move(eltsWithNoPayload)),
+ IGM(IGM), TIK(tik), AlwaysFixedSize(alwaysFixedSize),
+ ElementsAreABIAccessible(areElementsABIAccessible(ElementsWithPayload)),
+ NumElements(NumElements) {
+}
+
void irgen::EnumImplStrategy::initializeFromParams(IRGenFunction &IGF,
Explosion ¶ms,
Address dest, SILType T,
@@ -465,7 +488,9 @@
void assignWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
if (!getSingleton()) return;
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitAssignWithCopyCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
dest = getSingletonAddress(IGF, dest);
src = getSingletonAddress(IGF, src);
getSingleton()->assignWithCopy(
@@ -478,7 +503,9 @@
void assignWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
if (!getSingleton()) return;
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitAssignWithTakeCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
dest = getSingletonAddress(IGF, dest);
src = getSingletonAddress(IGF, src);
getSingleton()->assignWithTake(
@@ -498,7 +525,9 @@
void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
if (!getSingleton()) return;
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitInitializeWithCopyCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
dest = getSingletonAddress(IGF, dest);
src = getSingletonAddress(IGF, src);
getSingleton()->initializeWithCopy(
@@ -511,7 +540,9 @@
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
if (!getSingleton()) return;
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitInitializeWithTakeCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
dest = getSingletonAddress(IGF, dest);
src = getSingletonAddress(IGF, src);
getSingleton()->initializeWithTake(
@@ -555,7 +586,9 @@
bool isOutlined) const override {
if (getSingleton() &&
!getSingleton()->isPOD(ResilienceExpansion::Maximal)) {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitDestroyCall(IGF, T, addr);
+ } else if (isOutlined || T.hasOpenedExistential()) {
getSingleton()->destroy(IGF, getSingletonAddress(IGF, addr),
getSingletonType(IGF.IGM, T), isOutlined);
} else {
@@ -1478,6 +1511,8 @@
Normal,
/// The payload is POD, so copying is bitwise, and destruction is a noop.
POD,
+ /// The payload type is ABI-inaccessible, so we can't recurse.
+ ABIInaccessible,
/// The payload is a single reference-counted value, and we have
/// a single no-payload case which uses the null extra inhabitant, so
/// copy and destroy can pass through to retain and release entry
@@ -1595,7 +1630,9 @@
// If the payload is POD, then we can use POD value semantics.
auto &payloadTI = *ElementsWithPayload[0].ti;
- if (payloadTI.isPOD(ResilienceExpansion::Maximal)) {
+ if (!payloadTI.isABIAccessible()) {
+ CopyDestroyKind = ABIInaccessible;
+ } else if (payloadTI.isPOD(ResilienceExpansion::Maximal)) {
CopyDestroyKind = POD;
// If the payload is a single refcounted pointer and we have a single
// empty case, then the layout will be a nullable pointer, and we can
@@ -2217,6 +2254,7 @@
return IGM.getReferenceType(Refcounting);
case POD:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
@@ -2231,6 +2269,7 @@
return;
case POD:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
}
@@ -2243,6 +2282,7 @@
return;
case POD:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
}
@@ -2255,6 +2295,7 @@
return;
case POD:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
}
@@ -2281,6 +2322,9 @@
reexplode(IGF, src, dest);
return;
+ case ABIInaccessible:
+ llvm_unreachable("ABI-inaccessible type cannot be loadable");
+
case Normal: {
if (!copyEnumFunction)
copyEnumFunction = emitCopyEnumFunction(IGF.IGM, loweredType);
@@ -2315,6 +2359,9 @@
(void)src.claim(getExplosionSize());
return;
+ case ABIInaccessible:
+ llvm_unreachable("ABI-inaccessible type cannot be loadable");
+
case Normal: {
if (!consumeEnumFunction)
consumeEnumFunction = emitConsumeEnumFunction(IGF.IGM, loweredType);
@@ -2345,6 +2392,9 @@
(void)src.claim(getExplosionSize());
return;
+ case ABIInaccessible:
+ llvm_unreachable("ABI-inaccessible type cannot be loadable");
+
case Normal: {
// Check that we have a payload.
EnumPayload payload; llvm::Value *extraTag;
@@ -2385,11 +2435,16 @@
if (CopyDestroyKind == POD) {
return;
}
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ return emitDestroyCall(IGF, T, addr);
+ } else if (isOutlined || T.hasOpenedExistential()) {
switch (CopyDestroyKind) {
case POD:
return;
+ case ABIInaccessible:
+ llvm_unreachable("should already have been handled");
+
case Normal: {
// Check that there is a payload at the address.
llvm::BasicBlock *endBB = testEnumContainsPayload(IGF, addr, T);
@@ -2475,6 +2530,9 @@
case POD:
return emitPrimitiveCopy(IGF, dest, src, T);
+ case ABIInaccessible:
+ llvm_unreachable("shouldn't get here");
+
case Normal: {
llvm::BasicBlock *endBB = llvm::BasicBlock::Create(C);
@@ -2582,6 +2640,9 @@
case POD:
return emitPrimitiveCopy(IGF, dest, src, T);
+ case ABIInaccessible:
+ llvm_unreachable("shouldn't get here");
+
case Normal: {
llvm::BasicBlock *endBB = llvm::BasicBlock::Create(C);
@@ -2638,7 +2699,9 @@
public:
void assignWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitAssignWithCopyCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectAssign(IGF, dest, src, T, IsNotTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsNotInitialization, IsNotTake);
@@ -2647,7 +2710,9 @@
void assignWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitAssignWithTakeCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectAssign(IGF, dest, src, T, IsTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsNotInitialization, IsTake);
@@ -2656,7 +2721,9 @@
void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitInitializeWithCopyCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectInitialize(IGF, dest, src, T, IsNotTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsNotTake);
@@ -2665,7 +2732,9 @@
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitInitializeWithTakeCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectInitialize(IGF, dest, src, T, IsTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsTake);
@@ -2932,6 +3001,8 @@
/// The payloads are all POD, so copying is bitwise, and destruction is a
/// noop.
POD,
+ /// One or more of the payloads is ABI-inaccessible, so we cannot recurse.
+ ABIInaccessible,
/// The payloads are all bitwise-takable, but have no other special
/// shared layout.
BitwiseTakable,
@@ -3073,7 +3144,9 @@
}
}
- if (allPOD) {
+ if (!ElementsAreABIAccessible) {
+ CopyDestroyKind = ABIInaccessible;
+ } else if (allPOD) {
assert(!allSingleRefcount && "pod *and* refcounted?!");
CopyDestroyKind = POD;
// FIXME: Memory corruption issues arise when enabling this for mixed
@@ -3168,6 +3241,7 @@
case POD:
case BitwiseTakable:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
@@ -3183,6 +3257,7 @@
case POD:
case BitwiseTakable:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
}
@@ -3196,6 +3271,7 @@
case POD:
case BitwiseTakable:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
}
@@ -3209,6 +3285,7 @@
case POD:
case BitwiseTakable:
case Normal:
+ case ABIInaccessible:
llvm_unreachable("not a refcounted payload");
}
}
@@ -3989,6 +4066,9 @@
reexplode(IGF, src, dest);
return;
+ case ABIInaccessible:
+ llvm_unreachable("ABI-accessible type cannot be loadable");
+
case BitwiseTakable:
case Normal: {
if (!copyEnumFunction)
@@ -4031,6 +4111,9 @@
(void)src.claim(getExplosionSize());
return;
+ case ABIInaccessible:
+ llvm_unreachable("ABI-accessible type cannot be loadable");
+
case BitwiseTakable:
case Normal: {
if (!consumeEnumFunction)
@@ -4064,6 +4147,9 @@
(void)src.claim(getExplosionSize());
return;
+ case ABIInaccessible:
+ llvm_unreachable("ABI-accessible type cannot be loadable");
+
case BitwiseTakable:
case Normal: {
auto parts = destructureAndTagLoadableEnum(IGF, src);
@@ -4103,6 +4189,9 @@
case POD:
return emitPrimitiveCopy(IGF, dest, src, T);
+ case ABIInaccessible:
+ llvm_unreachable("shouldn't get here");
+
case BitwiseTakable:
case TaggedRefcounted:
case Normal: {
@@ -4153,6 +4242,9 @@
case POD:
return emitPrimitiveCopy(IGF, dest, src, T);
+ case ABIInaccessible:
+ llvm_unreachable("shouldn't get here");
+
case BitwiseTakable:
case TaggedRefcounted:
// Takes can be done by primitive copy in these case.
@@ -4277,7 +4369,9 @@
public:
void assignWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitAssignWithCopyCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectAssign(IGF, dest, src, T, IsNotTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsNotInitialization, IsNotTake);
@@ -4286,7 +4380,9 @@
void assignWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitAssignWithTakeCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectAssign(IGF, dest, src, T, IsTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsNotInitialization, IsTake);
@@ -4295,7 +4391,9 @@
void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitInitializeWithCopyCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectInitialize(IGF, dest, src, T, IsNotTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsNotTake);
@@ -4304,7 +4402,9 @@
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitInitializeWithTakeCall(IGF, T, dest, src);
+ } else if (isOutlined || T.hasOpenedExistential()) {
emitIndirectInitialize(IGF, dest, src, T, IsTake, isOutlined);
} else {
callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsTake);
@@ -4332,11 +4432,16 @@
if (CopyDestroyKind == POD) {
return;
}
- if (isOutlined || T.hasOpenedExistential()) {
+ if (!ElementsAreABIAccessible) {
+ emitDestroyCall(IGF, T, addr);
+ } else if (isOutlined || T.hasOpenedExistential()) {
switch (CopyDestroyKind) {
case POD:
return;
+ case ABIInaccessible:
+ llvm_unreachable("shouldn't get here");
+
case BitwiseTakable:
case Normal:
case TaggedRefcounted: {
@@ -5395,8 +5500,9 @@
llvm::Type *irTy,
Alignment align,
IsPOD_t pod,
- IsBitwiseTakable_t bt)
- : EnumTypeInfoBase(strategy, irTy, align, pod, bt) {}
+ IsBitwiseTakable_t bt,
+ IsABIAccessible_t abiAccessible)
+ : EnumTypeInfoBase(strategy, irTy, align, pod, bt, abiAccessible) {}
};
/// TypeInfo for dynamically-sized enum types.
@@ -5405,8 +5511,8 @@
{
public:
ResilientEnumTypeInfo(EnumImplStrategy &strategy,
- llvm::Type *irTy)
- : EnumTypeInfoBase(strategy, irTy) {}
+ llvm::Type *irTy, IsABIAccessible_t abiAccessible)
+ : EnumTypeInfoBase(strategy, irTy, abiAccessible) {}
};
} // end anonymous namespace
@@ -5479,10 +5585,13 @@
auto alignment = eltTI.getBestKnownAlignment();
applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/false,
alignment);
+ auto enumAccessible =
+ IsABIAccessible_t(TC.IGM.getSILModule().isTypeABIAccessible(Type));
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
alignment,
eltTI.isPOD(ResilienceExpansion::Maximal),
- eltTI.isBitwiseTakable(ResilienceExpansion::Maximal)));
+ eltTI.isBitwiseTakable(ResilienceExpansion::Maximal),
+ enumAccessible));
} else {
auto &fixedEltTI = cast<FixedTypeInfo>(eltTI);
auto alignment = fixedEltTI.getFixedAlignment();
@@ -5668,10 +5777,14 @@
applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/false,
alignment);
+ auto enumAccessible =
+ IsABIAccessible_t(TC.IGM.getSILModule().isTypeABIAccessible(Type));
+
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
alignment,
payloadTI.isPOD(ResilienceExpansion::Maximal),
- payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal)));
+ payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal),
+ enumAccessible));
}
TypeInfo *
@@ -5866,9 +5979,13 @@
applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/false,
alignment);
+
+ auto enumAccessible =
+ IsABIAccessible_t(TC.IGM.getSILModule().isTypeABIAccessible(Type));
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
- alignment, pod, bt));
+ alignment, pod, bt,
+ enumAccessible));
}
TypeInfo *
@@ -5887,7 +6004,10 @@
SILType Type,
EnumDecl *theEnum,
llvm::StructType *enumTy) {
- return registerEnumTypeInfo(new ResilientEnumTypeInfo(*this, enumTy));
+ auto abiAccessible =
+ IsABIAccessible_t(TC.IGM.getSILModule().isTypeABIAccessible(Type));
+ return registerEnumTypeInfo(
+ new ResilientEnumTypeInfo(*this, enumTy, abiAccessible));
}
const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h
index 8531f2b..c8c29aa 100644
--- a/lib/IRGen/GenEnum.h
+++ b/lib/IRGen/GenEnum.h
@@ -138,6 +138,7 @@
const TypeInfo *TI = nullptr;
TypeInfoKind TIK;
IsFixedSize_t AlwaysFixedSize;
+ IsABIAccessible_t ElementsAreABIAccessible;
unsigned NumElements;
EnumImplStrategy(IRGenModule &IGM,
@@ -145,12 +146,7 @@
IsFixedSize_t alwaysFixedSize,
unsigned NumElements,
std::vector<Element> &&ElementsWithPayload,
- std::vector<Element> &&ElementsWithNoPayload)
- : ElementsWithPayload(std::move(ElementsWithPayload)),
- ElementsWithNoPayload(std::move(ElementsWithNoPayload)),
- IGM(IGM), TIK(tik), AlwaysFixedSize(alwaysFixedSize),
- NumElements(NumElements)
- {}
+ std::vector<Element> &&ElementsWithNoPayload);
/// Save the TypeInfo created for the enum.
TypeInfo *registerEnumTypeInfo(TypeInfo *mutableTI) {
diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp
index a336b94..536fa32 100644
--- a/lib/IRGen/GenOpaque.cpp
+++ b/lib/IRGen/GenOpaque.cpp
@@ -388,6 +388,11 @@
return witness;
}
+static llvm::Value *emitCastToOpaquePtr(IRGenFunction &IGF,
+ Address object) {
+ return IGF.Builder.CreateBitCast(object.getAddress(), IGF.IGM.OpaquePtrTy);
+}
+
llvm::Value *irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF,
SILType T,
Address destBuffer,
@@ -529,10 +534,8 @@
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithCopyFn(),
{dest, src, count, metadata});
}
@@ -544,10 +547,8 @@
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithTakeNoAliasFn(),
{dest, src, count, metadata});
}
@@ -559,10 +560,8 @@
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithTakeFrontToBackFn(),
{dest, src, count, metadata});
}
@@ -574,10 +573,8 @@
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithTakeBackToFrontFn(),
{dest, src, count, metadata});
}
@@ -590,8 +587,9 @@
llvm::Value *metadata;
auto copyFn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::AssignWithCopy);
- IGF.Builder.CreateCall(copyFn,
- {destObject.getAddress(), srcObject.getAddress(), metadata});
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
+ IGF.Builder.CreateCall(copyFn, {dest, src, metadata});
}
/// Emit a call to do an 'assignWithCopy' operation.
@@ -601,8 +599,9 @@
Address srcObject) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(IGF, metadata,
ValueWitness::AssignWithCopy);
- IGF.Builder.CreateCall(copyFn,
- {destObject.getAddress(), srcObject.getAddress(), metadata});
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
+ IGF.Builder.CreateCall(copyFn, {dest, src, metadata});
}
/// Emit a call to do an 'arrayAssignWithCopyNoAlias' operation.
@@ -610,10 +609,8 @@
Address destObject, Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithCopyNoAliasFn(),
{dest, src, count, metadata});
}
@@ -625,10 +622,8 @@
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithCopyFrontToBackFn(),
{dest, src, count, metadata});
}
@@ -640,10 +635,8 @@
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithCopyBackToFrontFn(),
{dest, src, count, metadata});
}
@@ -656,8 +649,9 @@
llvm::Value *metadata;
auto copyFn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::AssignWithTake);
- IGF.Builder.CreateCall(copyFn,
- {destObject.getAddress(), srcObject.getAddress(), metadata});
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
+ IGF.Builder.CreateCall(copyFn, {dest, src, metadata});
}
/// Emit a call to do an 'arrayAssignWithTake' operation.
@@ -665,10 +659,8 @@
Address destObject, Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto dest =
- IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
- auto src =
- IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithTakeFn(),
{dest, src, count, metadata});
}
@@ -683,8 +675,7 @@
return;
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
- auto obj =
- IGF.Builder.CreateBitCast(object.getAddress(), IGF.IGM.OpaquePtrTy);
+ auto obj = emitCastToOpaquePtr(IGF, object);
IGF.Builder.CreateCall(IGF.IGM.getArrayDestroyFn(), {obj, count, metadata});
}
@@ -696,9 +687,10 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::GetExtraInhabitantIndex);
-
+
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
llvm::CallInst *call =
- IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata});
+ IGF.Builder.CreateCall(fn, {src, metadata});
return call;
}
@@ -711,8 +703,9 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::StoreExtraInhabitant);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
llvm::CallInst *call =
- IGF.Builder.CreateCall(fn, {destObject.getAddress(), index, metadata});
+ IGF.Builder.CreateCall(fn, {dest, index, metadata});
return call;
}
@@ -783,16 +776,15 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(
T, metadata, ValueWitness::GetEnumTagSinglePayload);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
llvm::CallInst *call = IGF.Builder.CreateCall(
- fn, {destObject.getAddress(), numEmptyCases, metadata});
+ fn, {dest, numEmptyCases, metadata});
return call;
}
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
auto *func = getGetEnumTagSinglePayloadTrampolineFn(IGF.IGM);
- auto *result = IGF.Builder.CreateCall(
- func,
- {IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy),
- numEmptyCases, metadata});
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto *result = IGF.Builder.CreateCall(func, {dest, numEmptyCases, metadata});
return result;
}
@@ -803,17 +795,17 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(
T, metadata, ValueWitness::StoreEnumTagSinglePayload);
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
llvm::CallInst *call = IGF.Builder.CreateCall(
- fn, {destObject.getAddress(), whichCase, numEmptyCases, metadata});
+ fn, {dest, whichCase, numEmptyCases, metadata});
return call;
}
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
auto *func = getStoreEnumTagSinglePayloadTrampolineFn(IGF.IGM);
- auto *result = IGF.Builder.CreateCall(
- func,
- {IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy),
- whichCase, numEmptyCases, metadata});
+ auto dest = emitCastToOpaquePtr(IGF, destObject);
+ auto *result = IGF.Builder.CreateCall(func,
+ {dest, whichCase, numEmptyCases, metadata});
return result;
}
@@ -825,8 +817,9 @@
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::GetEnumTag);
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
llvm::CallInst *call =
- IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata});
+ IGF.Builder.CreateCall(fn, {src, metadata});
return call;
}
@@ -838,7 +831,8 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::DestructiveProjectEnumData);
- IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata});
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
+ IGF.Builder.CreateCall(fn, {src, metadata});
}
/// Emit a call to the 'destructiveInjectEnumTag' operation.
@@ -850,7 +844,8 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::DestructiveInjectEnumTag);
- IGF.Builder.CreateCall(fn, {srcObject.getAddress(), tagValue, metadata});
+ auto src = emitCastToOpaquePtr(IGF, srcObject);
+ IGF.Builder.CreateCall(fn, {src, tagValue, metadata});
}
/// Load the 'size' value witness from the given table as a size_t.
@@ -950,7 +945,9 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithCopy);
- IGF.Builder.CreateCall(fn, {dest.getAddress(), src.getAddress(), metadata});
+ auto destPtr = emitCastToOpaquePtr(IGF, dest);
+ auto srcPtr = emitCastToOpaquePtr(IGF, src);
+ IGF.Builder.CreateCall(fn, {destPtr, srcPtr, metadata});
}
llvm::Value *irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
@@ -958,8 +955,10 @@
Address dest, Address src) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(
IGF, metadata, ValueWitness::InitializeWithCopy);
+ auto destPtr = emitCastToOpaquePtr(IGF, dest);
+ auto srcPtr = emitCastToOpaquePtr(IGF, src);
llvm::CallInst *call = IGF.Builder.CreateCall(
- copyFn, {dest.getAddress(), src.getAddress(), metadata});
+ copyFn, {destPtr, srcPtr, metadata});
return call;
}
@@ -972,7 +971,9 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithTake);
- IGF.Builder.CreateCall(fn, {dest.getAddress(), src.getAddress(), metadata});
+ auto destPtr = emitCastToOpaquePtr(IGF, dest);
+ auto srcPtr = emitCastToOpaquePtr(IGF, src);
+ IGF.Builder.CreateCall(fn, {destPtr, srcPtr, metadata});
}
llvm::Value *irgen::emitInitializeWithTakeCall(IRGenFunction &IGF,
@@ -980,8 +981,10 @@
Address dest, Address src) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(
IGF, metadata, ValueWitness::InitializeWithTake);
- llvm::CallInst *call = IGF.Builder.CreateCall(
- copyFn, {dest.getAddress(), src.getAddress(), metadata});
+ auto destPtr = emitCastToOpaquePtr(IGF, dest);
+ auto srcPtr = emitCastToOpaquePtr(IGF, src);
+ llvm::CallInst *call =
+ IGF.Builder.CreateCall(copyFn, {destPtr, srcPtr, metadata});
return call;
}
@@ -996,14 +999,16 @@
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::Destroy);
- IGF.Builder.CreateCall(fn, {object.getAddress(), metadata});
+ auto objectPtr = emitCastToOpaquePtr(IGF, object);
+ IGF.Builder.CreateCall(fn, {objectPtr, metadata});
}
void irgen::emitDestroyCall(IRGenFunction &IGF, llvm::Value *metadata,
Address object) {
auto fn = emitLoadOfValueWitnessFunctionFromMetadata(IGF, metadata,
ValueWitness::Destroy);
- IGF.Builder.CreateCall(fn, {object.getAddress(), metadata});
+ auto objectPtr = emitCastToOpaquePtr(IGF, object);
+ IGF.Builder.CreateCall(fn, {objectPtr, metadata});
}
static llvm::Constant *getAllocateValueBufferFunction(IRGenModule &IGM) {
diff --git a/lib/IRGen/GenRecord.h b/lib/IRGen/GenRecord.h
index b80a73d..ca29b14 100644
--- a/lib/IRGen/GenRecord.h
+++ b/lib/IRGen/GenRecord.h
@@ -22,6 +22,7 @@
#include "IRGenModule.h"
#include "Explosion.h"
#include "GenEnum.h"
+#include "GenOpaque.h"
#include "LoadableTypeInfo.h"
#include "Outlining.h"
#include "TypeInfo.h"
@@ -69,6 +70,10 @@
return Layout.isPOD();
}
+ IsABIAccessible_t isABIAccessible() const {
+ return Layout.getTypeForLayout().isABIAccessible();
+ }
+
Address projectAddress(IRGenFunction &IGF, Address seq,
NonFixedOffsets offsets) const {
return Layout.project(IGF, seq, offsets, "." + asImpl()->getFieldName());
@@ -93,6 +98,11 @@
}
};
+enum FieldsAreABIAccessible_t : bool {
+ FieldsAreNotABIAccessible = false,
+ FieldsAreABIAccessible = true,
+};
+
/// A metaprogrammed TypeInfo implementation for record types.
template <class Impl, class Base, class FieldImpl_,
bool IsLoadable = std::is_base_of<LoadableTypeInfo, Base>::value>
@@ -105,13 +115,18 @@
private:
const unsigned NumFields;
+ const unsigned AreFieldsABIAccessible : 1;
protected:
const Impl &asImpl() const { return *static_cast<const Impl*>(this); }
template <class... As>
- RecordTypeInfoImpl(ArrayRef<FieldImpl> fields, As&&...args)
- : Base(std::forward<As>(args)...), NumFields(fields.size()) {
+ RecordTypeInfoImpl(ArrayRef<FieldImpl> fields,
+ FieldsAreABIAccessible_t fieldsABIAccessible,
+ As&&...args)
+ : Base(std::forward<As>(args)...),
+ NumFields(fields.size()),
+ AreFieldsABIAccessible(fieldsABIAccessible) {
std::uninitialized_copy(fields.begin(), fields.end(),
this->template getTrailingObjects<FieldImpl>());
}
@@ -138,6 +153,11 @@
void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T,
bool isOutlined) const override {
+ // If the fields are not ABI-accessible, use the value witness table.
+ if (!AreFieldsABIAccessible) {
+ return emitAssignWithCopyCall(IGF, T, dest, src);
+ }
+
if (isOutlined || T.hasOpenedExistential()) {
auto offsets = asImpl().getNonFixedOffsets(IGF, T);
for (auto &field : getFields()) {
@@ -156,6 +176,11 @@
void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T,
bool isOutlined) const override {
+ // If the fields are not ABI-accessible, use the value witness table.
+ if (!AreFieldsABIAccessible) {
+ return emitAssignWithTakeCall(IGF, T, dest, src);
+ }
+
if (isOutlined || T.hasOpenedExistential()) {
auto offsets = asImpl().getNonFixedOffsets(IGF, T);
for (auto &field : getFields()) {
@@ -181,6 +206,11 @@
IGF, dest, src, T, isOutlined);
}
+ // If the fields are not ABI-accessible, use the value witness table.
+ if (!AreFieldsABIAccessible) {
+ return emitInitializeWithCopyCall(IGF, T, dest, src);
+ }
+
if (isOutlined || T.hasOpenedExistential()) {
auto offsets = asImpl().getNonFixedOffsets(IGF, T);
for (auto &field : getFields()) {
@@ -207,6 +237,11 @@
return;
}
+ // If the fields are not ABI-accessible, use the value witness table.
+ if (!AreFieldsABIAccessible) {
+ return emitInitializeWithTakeCall(IGF, T, dest, src);
+ }
+
if (isOutlined || T.hasOpenedExistential()) {
auto offsets = asImpl().getNonFixedOffsets(IGF, T);
for (auto &field : getFields()) {
@@ -225,6 +260,11 @@
void destroy(IRGenFunction &IGF, Address addr, SILType T,
bool isOutlined) const override {
+ // If the fields are not ABI-accessible, use the value witness table.
+ if (!AreFieldsABIAccessible) {
+ return emitDestroyCall(IGF, T, addr);
+ }
+
if (isOutlined || T.hasOpenedExistential()) {
auto offsets = asImpl().getNonFixedOffsets(IGF, T);
for (auto &field : getFields()) {
@@ -323,6 +363,9 @@
// Ignore empty fields.
if (field.isEmpty()) continue;
+ // If the field is not ABI-accessible, suppress this.
+ if (!field.isABIAccessible()) continue;
+
// If we've already found an index, then there isn't a
// unique non-empty field.
if (result) return 0;
@@ -351,7 +394,8 @@
protected:
template <class... As>
- RecordTypeInfo(As&&...args) : super(std::forward<As>(args)...) {}
+ RecordTypeInfo(ArrayRef<FieldImpl> fields, As &&...args)
+ : super(fields, FieldsAreABIAccessible, std::forward<As>(args)...) {}
};
/// An implementation of RecordTypeInfo for loadable types.
@@ -367,9 +411,10 @@
using super::asImpl;
template <class... As>
- RecordTypeInfo(ArrayRef<FieldImpl> fields, unsigned explosionSize,
+ RecordTypeInfo(ArrayRef<FieldImpl> fields,
+ unsigned explosionSize,
As &&...args)
- : super(fields, std::forward<As>(args)...),
+ : super(fields, FieldsAreABIAccessible, std::forward<As>(args)...),
ExplosionSize(explosionSize) {}
private:
@@ -518,6 +563,7 @@
fieldTypesForLayout.reserve(astFields.size());
bool loadable = true;
+ auto fieldsABIAccessible = FieldsAreABIAccessible;
unsigned explosionSize = 0;
for (unsigned i : indices(astFields)) {
@@ -527,6 +573,9 @@
assert(fieldTI.isComplete());
fieldTypesForLayout.push_back(&fieldTI);
+ if (!fieldTI.isABIAccessible())
+ fieldsABIAccessible = FieldsAreNotABIAccessible;
+
fields.push_back(FieldImpl(asImpl()->getFieldInfo(i, astField, fieldTI)));
auto loadableFieldTI = dyn_cast<LoadableTypeInfo>(&fieldTI);
@@ -550,11 +599,14 @@
// Create the type info.
if (loadable) {
assert(layout.isFixedLayout());
+ assert(fieldsABIAccessible);
return asImpl()->createLoadable(fields, std::move(layout), explosionSize);
} else if (layout.isFixedLayout()) {
+ assert(fieldsABIAccessible);
return asImpl()->createFixed(fields, std::move(layout));
} else {
- return asImpl()->createNonFixed(fields, std::move(layout));
+ return asImpl()->createNonFixed(fields, fieldsABIAccessible,
+ std::move(layout));
}
}
};
diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp
index 0ebd76a..2174148 100644
--- a/lib/IRGen/GenStruct.cpp
+++ b/lib/IRGen/GenStruct.cpp
@@ -494,11 +494,15 @@
WitnessSizedTypeInfo<NonFixedStructTypeInfo>>
{
public:
- NonFixedStructTypeInfo(ArrayRef<StructFieldInfo> fields, llvm::Type *T,
+ NonFixedStructTypeInfo(ArrayRef<StructFieldInfo> fields,
+ FieldsAreABIAccessible_t fieldsAccessible,
+ llvm::Type *T,
Alignment align,
- IsPOD_t isPOD, IsBitwiseTakable_t isBT)
+ IsPOD_t isPOD, IsBitwiseTakable_t isBT,
+ IsABIAccessible_t structAccessible)
: StructTypeInfoBase(StructTypeInfoKind::NonFixedStructTypeInfo,
- fields, T, align, isPOD, isBT) {
+ fields, fieldsAccessible,
+ T, align, isPOD, isBT, structAccessible) {
}
// We have an indirect schema.
@@ -556,11 +560,16 @@
}
NonFixedStructTypeInfo *createNonFixed(ArrayRef<StructFieldInfo> fields,
+ FieldsAreABIAccessible_t fieldsAccessible,
StructLayout &&layout) {
- return NonFixedStructTypeInfo::create(fields, layout.getType(),
+ auto structAccessible = IsABIAccessible_t(
+ IGM.getSILModule().isTypeMetadataAccessible(TheStruct));
+ return NonFixedStructTypeInfo::create(fields, fieldsAccessible,
+ layout.getType(),
layout.getAlignment(),
layout.isPOD(),
- layout.isBitwiseTakable());
+ layout.isBitwiseTakable(),
+ structAccessible);
}
StructFieldInfo getFieldInfo(unsigned index,
@@ -871,24 +880,29 @@
: public ResilientTypeInfo<ResilientStructTypeInfo>
{
public:
- ResilientStructTypeInfo(llvm::Type *T)
- : ResilientTypeInfo(T) {
+ ResilientStructTypeInfo(llvm::Type *T, IsABIAccessible_t abiAccessible)
+ : ResilientTypeInfo(T, abiAccessible) {
setSubclassKind((unsigned) StructTypeInfoKind::ResilientStructTypeInfo);
}
};
} // end anonymous namespace
-const TypeInfo *TypeConverter::convertResilientStruct() {
+const TypeInfo *
+TypeConverter::convertResilientStruct(IsABIAccessible_t abiAccessible) {
llvm::Type *storageType = IGM.OpaquePtrTy->getElementType();
- return new ResilientStructTypeInfo(storageType);
+ return new ResilientStructTypeInfo(storageType, abiAccessible);
}
const TypeInfo *TypeConverter::convertStructType(TypeBase *key, CanType type,
StructDecl *D) {
// All resilient structs have the same opaque lowering, since they are
- // indistinguishable as values.
- if (IGM.isResilient(D, ResilienceExpansion::Maximal))
- return &getResilientStructTypeInfo();
+ // indistinguishable as values --- except that we have to track
+ // ABI-accessibility.
+ if (IGM.isResilient(D, ResilienceExpansion::Maximal)) {
+ auto structAccessible =
+ IsABIAccessible_t(IGM.getSILModule().isTypeMetadataAccessible(type));
+ return &getResilientStructTypeInfo(structAccessible);
+ }
// Create the struct type.
auto ty = IGM.createNominalType(type);
diff --git a/lib/IRGen/GenTuple.cpp b/lib/IRGen/GenTuple.cpp
index 1193fab..c424239 100644
--- a/lib/IRGen/GenTuple.cpp
+++ b/lib/IRGen/GenTuple.cpp
@@ -23,6 +23,7 @@
#include "swift/AST/Types.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Pattern.h"
+#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "llvm/IR/DerivedTypes.h"
@@ -331,10 +332,14 @@
WitnessSizedTypeInfo<NonFixedTupleTypeInfo>>
{
public:
- NonFixedTupleTypeInfo(ArrayRef<TupleFieldInfo> fields, llvm::Type *T,
+ NonFixedTupleTypeInfo(ArrayRef<TupleFieldInfo> fields,
+ FieldsAreABIAccessible_t fieldsABIAccessible,
+ llvm::Type *T,
Alignment minAlign, IsPOD_t isPOD,
- IsBitwiseTakable_t isBT)
- : TupleTypeInfoBase(fields, T, minAlign, isPOD, isBT) {}
+ IsBitwiseTakable_t isBT,
+ IsABIAccessible_t tupleAccessible)
+ : TupleTypeInfoBase(fields, fieldsABIAccessible,
+ T, minAlign, isPOD, isBT, tupleAccessible) {}
TupleNonFixedOffsets getNonFixedOffsets(IRGenFunction &IGF,
SILType T) const {
@@ -374,11 +379,16 @@
}
NonFixedTupleTypeInfo *createNonFixed(ArrayRef<TupleFieldInfo> fields,
+ FieldsAreABIAccessible_t fieldsAccessible,
StructLayout &&layout) {
- return NonFixedTupleTypeInfo::create(fields, layout.getType(),
+ auto tupleAccessible = IsABIAccessible_t(
+ IGM.getSILModule().isTypeABIAccessible(TheTuple));
+ return NonFixedTupleTypeInfo::create(fields, fieldsAccessible,
+ layout.getType(),
layout.getAlignment(),
layout.isPOD(),
- layout.isBitwiseTakable());
+ layout.isBitwiseTakable(),
+ tupleAccessible);
}
TupleFieldInfo getFieldInfo(unsigned index,
diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp
index 84f68ca..5ff6457 100644
--- a/lib/IRGen/GenType.cpp
+++ b/lib/IRGen/GenType.cpp
@@ -1243,12 +1243,15 @@
return *EmptyTI;
}
-const TypeInfo &TypeConverter::getResilientStructTypeInfo() {
- if (ResilientStructTI) return *ResilientStructTI;
- ResilientStructTI = convertResilientStruct();
- ResilientStructTI->NextConverted = FirstType;
- FirstType = ResilientStructTI;
- return *ResilientStructTI;
+const TypeInfo &
+TypeConverter::getResilientStructTypeInfo(IsABIAccessible_t isAccessible) {
+ auto &cache = isAccessible ? AccessibleResilientStructTI
+ : InaccessibleResilientStructTI;
+ if (cache) return *cache;
+ cache = convertResilientStruct(isAccessible);
+ cache->NextConverted = FirstType;
+ FirstType = cache;
+ return *cache;
}
/// Get the fragile type information for the given type, which may not
diff --git a/lib/IRGen/GenType.h b/lib/IRGen/GenType.h
index 3607b74..866a8d8 100644
--- a/lib/IRGen/GenType.h
+++ b/lib/IRGen/GenType.h
@@ -82,7 +82,8 @@
const LoadableTypeInfo *ObjCClassPtrTI = nullptr;
const LoadableTypeInfo *EmptyTI = nullptr;
- const TypeInfo *ResilientStructTI = nullptr;
+ const TypeInfo *AccessibleResilientStructTI = nullptr;
+ const TypeInfo *InaccessibleResilientStructTI = nullptr;
llvm::DenseMap<std::pair<unsigned, unsigned>, const LoadableTypeInfo *>
OpaqueStorageTypes;
@@ -123,7 +124,7 @@
const LoadableTypeInfo *convertBuiltinNativeObject();
const LoadableTypeInfo *convertBuiltinUnknownObject();
const LoadableTypeInfo *convertBuiltinBridgeObject();
- const TypeInfo *convertResilientStruct();
+ const TypeInfo *convertResilientStruct(IsABIAccessible_t abiAccessible);
const TypeInfo *convertUnmanagedStorageType(UnmanagedStorageType *T);
const TypeInfo *convertUnownedStorageType(UnownedStorageType *T);
const TypeInfo *convertWeakStorageType(WeakStorageType *T);
@@ -147,7 +148,7 @@
const LoadableTypeInfo &getObjCClassPtrTypeInfo();
const LoadableTypeInfo &getWitnessTablePtrTypeInfo();
const LoadableTypeInfo &getEmptyTypeInfo();
- const TypeInfo &getResilientStructTypeInfo();
+ const TypeInfo &getResilientStructTypeInfo(IsABIAccessible_t abiAccessible);
const ProtocolInfo &getProtocolInfo(ProtocolDecl *P);
const LoadableTypeInfo &getOpaqueStorageTypeInfo(Size storageSize,
Alignment storageAlign);
diff --git a/lib/IRGen/IRGen.h b/lib/IRGen/IRGen.h
index a02e958..9f5b485 100644
--- a/lib/IRGen/IRGen.h
+++ b/lib/IRGen/IRGen.h
@@ -33,7 +33,7 @@
class CanType;
class ClusteredBitVector;
enum ForDefinition_t : bool;
-
+
namespace irgen {
using Lowering::AbstractionPattern;
using clang::CodeGen::ConstantInitFuture;
@@ -77,6 +77,11 @@
return (l = (l & r));
}
+enum IsABIAccessible_t : bool {
+ IsNotABIAccessible = false,
+ IsABIAccessible = true
+};
+
/// The kind of reference counting implementation a heap object uses.
enum class ReferenceCounting : uint8_t {
/// The object uses native Swift reference counting.
diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp
index 9331989..c5ded19 100644
--- a/lib/IRGen/MetadataRequest.cpp
+++ b/lib/IRGen/MetadataRequest.cpp
@@ -1923,6 +1923,9 @@
/// not to cache the result as if it were the metadata for a formal type
/// unless the type actually cannot possibly be a formal type, e.g. because
/// it is one of the special lowered type kinds like SILFunctionType.
+ ///
+ /// NOTE: If you modify the special cases in this, you should update
+ /// isTypeMetadataForLayoutAccessible in SIL.cpp.
class EmitTypeMetadataRefForLayout
: public CanTypeVisitor<EmitTypeMetadataRefForLayout, llvm::Value *,
DynamicMetadataRequest> {
diff --git a/lib/IRGen/NonFixedTypeInfo.h b/lib/IRGen/NonFixedTypeInfo.h
index 1a01a96..5002961 100644
--- a/lib/IRGen/NonFixedTypeInfo.h
+++ b/lib/IRGen/NonFixedTypeInfo.h
@@ -52,8 +52,8 @@
const Impl &asImpl() const { return static_cast<const Impl &>(*this); }
WitnessSizedTypeInfo(llvm::Type *type, Alignment align, IsPOD_t pod,
- IsBitwiseTakable_t bt)
- : super(type, align, pod, bt, IsNotFixedSize, TypeInfo::STIK_None) {}
+ IsBitwiseTakable_t bt, IsABIAccessible_t abi)
+ : super(type, align, pod, bt, IsNotFixedSize, abi, TypeInfo::STIK_None) {}
private:
/// Bit-cast the given pointer to the right type and assume it as an
diff --git a/lib/IRGen/ResilientTypeInfo.h b/lib/IRGen/ResilientTypeInfo.h
index 0be4944..1672755 100644
--- a/lib/IRGen/ResilientTypeInfo.h
+++ b/lib/IRGen/ResilientTypeInfo.h
@@ -42,9 +42,10 @@
template <class Impl>
class ResilientTypeInfo : public WitnessSizedTypeInfo<Impl> {
protected:
- ResilientTypeInfo(llvm::Type *type)
+ ResilientTypeInfo(llvm::Type *type, IsABIAccessible_t abiAccessible)
: WitnessSizedTypeInfo<Impl>(type, Alignment(1),
- IsNotPOD, IsNotBitwiseTakable) {}
+ IsNotPOD, IsNotBitwiseTakable,
+ abiAccessible) {}
public:
void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T,
diff --git a/lib/IRGen/TypeInfo.h b/lib/IRGen/TypeInfo.h
index 36a8d7f..4fa6c2f 100644
--- a/lib/IRGen/TypeInfo.h
+++ b/lib/IRGen/TypeInfo.h
@@ -93,10 +93,12 @@
TypeInfo(llvm::Type *Type, Alignment A, IsPOD_t pod,
IsBitwiseTakable_t bitwiseTakable,
IsFixedSize_t alwaysFixedSize,
+ IsABIAccessible_t abiAccessible,
SpecialTypeInfoKind stik)
: NextConverted(0), StorageType(Type), nativeReturnSchema(nullptr),
nativeParameterSchema(nullptr), StorageAlignment(A),
POD(pod), BitwiseTakable(bitwiseTakable),
+ ABIAccessible(abiAccessible),
AlwaysFixedSize(alwaysFixedSize), STIK(stik),
SubclassKind(InvalidSubclassKind) {
assert(STIK >= STIK_Fixed || !AlwaysFixedSize);
@@ -134,6 +136,9 @@
/// Whether this type is known to be bitwise-takable.
unsigned BitwiseTakable : 1;
+ /// Whether this type is ABI-accessible from this SILModule.
+ unsigned ABIAccessible : 1;
+
/// Whether this type can be assumed to have a fixed size from all
/// resilience domains.
unsigned AlwaysFixedSize : 1;
@@ -161,6 +166,17 @@
/// Whether this type is known to be empty.
bool isKnownEmpty(ResilienceExpansion expansion) const;
+ /// Whether this type is known to be ABI-accessible, i.e. whether it's
+ /// actually possible to do ABI operations on it from this current SILModule.
+ /// See SILModule::isTypeABIAccessible.
+ ///
+ /// All fixed-size types are currently ABI-accessible, although this would
+ /// not be difficult to change (e.g. if we had an archetype size constraint
+ /// that didn't say anything about triviality).
+ IsABIAccessible_t isABIAccessible() const {
+ return IsABIAccessible_t(ABIAccessible);
+ }
+
/// Whether this type is known to be POD, i.e. to not require any
/// particular action on copy or destroy.
IsPOD_t isPOD(ResilienceExpansion expansion) const { return IsPOD_t(POD); }
diff --git a/lib/SIL/SIL.cpp b/lib/SIL/SIL.cpp
index ecbe6ac..b91261b 100644
--- a/lib/SIL/SIL.cpp
+++ b/lib/SIL/SIL.cpp
@@ -105,3 +105,101 @@
return (definition ? SILLinkage::Public : SILLinkage::PublicExternal);
}
}
+
+bool SILModule::isTypeMetadataAccessible(CanType type) {
+ assert(type->isLegalFormalType());
+
+ return !type.findIf([&](CanType type) {
+ // Note that this function returns true if the type is *illegal* to use.
+
+ // Ignore non-nominal types.
+ auto decl = type.getNominalOrBoundGenericNominal();
+ if (!decl)
+ return false;
+
+ // Check whether the declaration is inaccessible from the current context.
+ switch (getDeclLinkage(decl)) {
+
+ // Public declarations are accessible from everywhere.
+ case FormalLinkage::PublicUnique:
+ case FormalLinkage::PublicNonUnique:
+ return false;
+
+ // Hidden declarations are inaccessible from different modules.
+ case FormalLinkage::HiddenUnique:
+ return (decl->getModuleContext() != getSwiftModule());
+
+ // Private declarations are inaccessible from different files unless
+ // this is WMO and we're in the same module.
+ case FormalLinkage::Private: {
+ // The only time we don't have an associated DC is in the
+ // integrated REPL, where we also don't have a concept of other
+ // source files within the current module.
+ if (!AssociatedDeclContext)
+ return (decl->getModuleContext() != getSwiftModule());
+
+ // The associated DC should be either a SourceFile or, in WMO mode,
+ // a ModuleDecl. In the WMO modes, IRGen will ensure that private
+ // declarations are usable throughout the module. Therefore, in
+ // either case we just need to make sure that the declaration comes
+ // from within the associated DC.
+ auto declDC = decl->getDeclContext();
+ return !(declDC == AssociatedDeclContext ||
+ declDC->isChildContextOf(AssociatedDeclContext));
+ }
+ }
+ llvm_unreachable("bad linkage");
+ });
+}
+
+/// Answer whether IRGen's emitTypeMetadataForLayout can fetch metadata for
+/// a type, which is the necessary condition for being able to do value
+/// operations on the type using dynamic metadata.
+static bool isTypeMetadataForLayoutAccessible(SILModule &M, SILType type) {
+ // Look through types that aren't necessarily legal formal types:
+
+ // - tuples
+ if (auto tupleType = type.getAs<TupleType>()) {
+ for (auto index : indices(tupleType.getElementTypes())) {
+ if (!isTypeMetadataForLayoutAccessible(M, type.getTupleElementType(index)))
+ return false;
+ }
+ return true;
+ }
+
+ // - optionals
+ if (auto objType = type.getOptionalObjectType()) {
+ return isTypeMetadataForLayoutAccessible(M, objType);
+ }
+
+ // - function types
+ if (type.is<SILFunctionType>())
+ return true;
+
+ // - metatypes
+ if (type.is<AnyMetatypeType>())
+ return true;
+
+ // Otherwise, check that we can fetch the type metadata.
+ return M.isTypeMetadataAccessible(type.getSwiftRValueType());
+
+}
+
+/// Can we perform value operations on the given type? We have no way
+/// of doing value operations on resilient-layout types from other modules
+/// that are ABI-private to their defining module. But if the type is not
+/// ABI-private, we can always at least fetch its metadata and use the
+/// value witness table stored there.
+bool SILModule::isTypeABIAccessible(SILType type) {
+ // Fixed-ABI types can have value operations done without metadata.
+ if (Types.getTypeLowering(type).isFixedABI())
+ return true;
+
+ assert(!type.is<ReferenceStorageType>() &&
+ !type.is<SILFunctionType>() &&
+ !type.is<AnyMetatypeType>() &&
+ "unexpected SIL lowered-only type with non-fixed layout");
+
+ // Otherwise, we need to be able to fetch layout-metadata for the type.
+ return isTypeMetadataForLayoutAccessible(*this, type);
+}
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 662332d..c044f2b 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -1819,6 +1819,8 @@
"Dest address should be lvalue");
require(SI->getDest()->getType() == SI->getSrc()->getType(),
"Store operand type and dest type mismatch");
+ require(F.getModule().isTypeABIAccessible(SI->getDest()->getType()),
+ "cannot directly copy type with inaccessible ABI");
}
void checkRetainValueInst(RetainValueInst *I) {
@@ -2241,6 +2243,8 @@
void checkDestroyAddrInst(DestroyAddrInst *DI) {
require(DI->getOperand()->getType().isAddress(),
"Operand of destroy_addr must be address");
+ require(F.getModule().isTypeABIAccessible(DI->getOperand()->getType()),
+ "cannot directly destroy type with inaccessible ABI");
}
void checkBindMemoryInst(BindMemoryInst *BI) {
diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp
index fd15e47..eec5cd8 100644
--- a/lib/SIL/TypeLowering.cpp
+++ b/lib/SIL/TypeLowering.cpp
@@ -153,26 +153,11 @@
llvm_unreachable("function-like captures should have been lowered away");
}
-enum class LoweredTypeKind {
- /// Trivial and loadable.
- Trivial,
+using RecursiveProperties = TypeLowering::RecursiveProperties;
- /// A reference type.
- Reference,
-
- /// An aggregate type that contains references (potentially recursively).
- AggWithReference,
-
- /// Non-trivial and not loadable.
- AddressOnly,
-
- /// Trivial and not loadable.
- TrivialAddressOnly
-};
-
-static LoweredTypeKind classifyType(CanType type, SILModule &M,
- CanGenericSignature sig,
- ResilienceExpansion expansion);
+static RecursiveProperties
+classifyType(CanType type, SILModule &M, CanGenericSignature sig,
+ ResilienceExpansion expansion);
namespace {
/// A CRTP helper class for doing things that depends on type
@@ -190,13 +175,36 @@
public:
// The subclass should implement:
- // RetTy handleAddressOnly(CanType);
- // RetTy handleReference(CanType);
+ // // Trivial, fixed-layout, and non-address-only.
// RetTy handleTrivial(CanType);
- // RetTy handleTrivialAddressOnly(CanType);
- // In addition, if it does not override visitTupleType
- // and visitAnyStructType, it should also implement:
- // RetTy handleAggWithReference(CanType);
+ // // A reference type.
+ // RetTy handleReference(CanType);
+ // // Non-trivial and address-only.
+ // RetTy handleAddressOnly(CanType, RecursiveProperties properties);
+ // and, if it doesn't override handleTupleType,
+ // // An aggregate type that's non-trivial.
+ // RetTy handleNonTrivialAggregate(CanType, IsFixedABI_t fixed);
+ //
+ // Alternatively, it can just implement:
+ // RetTy handle(CanType, RecursiveProperties properties);
+
+ /// Handle a trivial, fixed-size, loadable type.
+ RetTy handleTrivial(CanType type) {
+ return asImpl().handle(type, RecursiveProperties());
+ }
+
+ RetTy handleReference(CanType type) {
+ return asImpl().handle(type, RecursiveProperties::forReference());
+ }
+
+ RetTy handleAddressOnly(CanType type, RecursiveProperties properties) {
+ return asImpl().handle(type, properties);
+ }
+
+ RetTy handleNonTrivialAggregate(CanType type,
+ RecursiveProperties properties) {
+ return asImpl().handle(type, properties);
+ }
#define IMPL(TYPE, LOWERING) \
RetTy visit##TYPE##Type(Can##TYPE##Type type) { \
@@ -209,14 +217,21 @@
IMPL(BuiltinNativeObject, Reference)
IMPL(BuiltinBridgeObject, Reference)
IMPL(BuiltinUnknownObject, Reference)
- IMPL(BuiltinUnsafeValueBuffer, AddressOnly)
IMPL(BuiltinVector, Trivial)
IMPL(SILToken, Trivial)
IMPL(Class, Reference)
IMPL(BoundGenericClass, Reference)
IMPL(AnyMetatype, Trivial)
IMPL(Module, Trivial)
-
+
+#undef IMPL
+
+ RetTy visitBuiltinUnsafeValueBufferType(
+ CanBuiltinUnsafeValueBufferType type) {
+ return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI,
+ IsAddressOnly});
+ }
+
RetTy visitAnyFunctionType(CanAnyFunctionType type) {
switch (type->getRepresentation()) {
case AnyFunctionType::Representation::Swift:
@@ -240,8 +255,6 @@
return asImpl().handleTrivial(type);
}
-#undef IMPL
-
RetTy visitLValueType(CanLValueType type) {
llvm_unreachable("shouldn't get an l-value type here");
}
@@ -268,7 +281,8 @@
return asImpl().visit(genericSig->getConcreteType(type)
->getCanonicalType());
} else {
- return asImpl().handleAddressOnly(type);
+ return asImpl().handleAddressOnly(type,
+ RecursiveProperties::forOpaque());
}
}
llvm_unreachable("should have substituted dependent type into context");
@@ -330,11 +344,15 @@
}
RetTy visitAddressOnlyUnownedStorageType(CanUnownedStorageType type) {
- return asImpl().handleAddressOnly(type);
+ return asImpl().handleAddressOnly(type, {IsNotTrivial,
+ IsFixedABI,
+ IsAddressOnly});
}
RetTy visitWeakStorageType(CanWeakStorageType type) {
- return asImpl().handleAddressOnly(type);
+ return asImpl().handleAddressOnly(type, {IsNotTrivial,
+ IsFixedABI,
+ IsAddressOnly});
}
RetTy visitArchetypeType(CanArchetypeType type) {
@@ -349,13 +367,14 @@
}
if (LayoutInfo->isAddressOnlyTrivial()) {
- return asImpl().handleTrivialAddressOnly(type);
+ return asImpl().handleAddressOnly(type,
+ {IsTrivial, IsNotFixedABI, IsAddressOnly});
}
if (LayoutInfo->isRefCounted())
return asImpl().handleReference(type);
}
- return asImpl().handleAddressOnly(type);
+ return asImpl().handleAddressOnly(type, RecursiveProperties::forOpaque());
}
RetTy visitExistentialType(CanType type) {
@@ -365,7 +384,9 @@
llvm_unreachable("not an existential type?!");
// Opaque existentials are address-only.
case ExistentialRepresentation::Opaque:
- return asImpl().handleAddressOnly(type);
+ return asImpl().handleAddressOnly(type, {IsNotTrivial,
+ IsFixedABI,
+ IsAddressOnly});
// Class-constrained and boxed existentials are refcounted.
case ExistentialRepresentation::Class:
case ExistentialRepresentation::Boxed:
@@ -402,26 +423,11 @@
// Tuples depend on their elements.
RetTy visitTupleType(CanTupleType type) {
- bool hasReference = false;
+ RecursiveProperties props;
for (auto eltType : type.getElementTypes()) {
- switch (classifyType(eltType, M, Sig, Expansion)) {
- case LoweredTypeKind::Trivial:
- continue;
- case LoweredTypeKind::TrivialAddressOnly:
- return asImpl().handleTrivialAddressOnly(type);
- case LoweredTypeKind::AddressOnly:
- return asImpl().handleAddressOnly(type);
- case LoweredTypeKind::Reference:
- case LoweredTypeKind::AggWithReference:
- hasReference = true;
- continue;
- }
- llvm_unreachable("bad type classification");
+ props.addSubobject(classifyType(eltType, M, Sig, Expansion));
}
-
- if (hasReference)
- return asImpl().handleAggWithReference(type);
- return asImpl().handleTrivial(type);
+ return asImpl().handleAggregateByProperties(type, props);
}
RetTy visitDynamicSelfType(CanDynamicSelfType type) {
@@ -430,43 +436,39 @@
RetTy visitSILBlockStorageType(CanSILBlockStorageType type) {
// Should not be loaded.
- return asImpl().handleAddressOnly(type);
+ return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI,
+ IsAddressOnly});
}
RetTy visitSILBoxType(CanSILBoxType type) {
// Should not be loaded.
return asImpl().handleReference(type);
}
+
+ RetTy handleAggregateByProperties(CanType type, RecursiveProperties props) {
+ if (props.isAddressOnly()) {
+ return asImpl().handleAddressOnly(type, props);
+ }
+ assert(props.isFixedABI() && "unsupported combination for now");
+ if (props.isTrivial()) {
+ return asImpl().handleTrivial(type);
+ }
+ return asImpl().handleNonTrivialAggregate(type, props);
+ }
};
class TypeClassifier :
- public TypeClassifierBase<TypeClassifier, LoweredTypeKind> {
+ public TypeClassifierBase<TypeClassifier, RecursiveProperties> {
public:
TypeClassifier(SILModule &M, CanGenericSignature Sig,
ResilienceExpansion Expansion)
: TypeClassifierBase(M, Sig, Expansion) {}
- LoweredTypeKind handleReference(CanType type) {
- return LoweredTypeKind::Reference;
- }
- LoweredTypeKind handleAggWithReference(CanType type) {
- return LoweredTypeKind::AggWithReference;
- }
- LoweredTypeKind
- handleTrivial(CanType type) {
- return LoweredTypeKind::Trivial;
+ RecursiveProperties handle(CanType type, RecursiveProperties properties) {
+ return properties;
}
- LoweredTypeKind
- handleTrivialAddressOnly(CanType type) {
- return LoweredTypeKind::TrivialAddressOnly;
- }
-
- LoweredTypeKind handleAddressOnly(CanType type) {
- return LoweredTypeKind::AddressOnly;
- }
-
- LoweredTypeKind visitAnyEnumType(CanType type, EnumDecl *D) {
+ RecursiveProperties visitAnyEnumType(CanType type, EnumDecl *D) {
// We have to look through optionals here without grabbing the
// type lowering because the way that optionals are reabstracted
// can trip recursion checks if we try to build a lowered type.
@@ -480,7 +482,7 @@
return handleClassificationFromLowering(type, lowering);
}
- LoweredTypeKind visitAnyStructType(CanType type, StructDecl *D) {
+ RecursiveProperties visitAnyStructType(CanType type, StructDecl *D) {
// Consult the type lowering.
type = getSubstitutedTypeForTypeLowering(type);
auto &lowering = M.Types.getTypeLowering(type);
@@ -504,20 +506,16 @@
return type;
}
- LoweredTypeKind handleClassificationFromLowering(CanType type,
+ RecursiveProperties handleClassificationFromLowering(CanType type,
const TypeLowering &lowering) {
- if (lowering.isAddressOnly())
- return handleAddressOnly(type);
- if (lowering.isTrivial())
- return handleTrivial(type);
- return handleAggWithReference(type);
+ return handle(type, lowering.getRecursiveProperties());
}
};
} // end anonymous namespace
-static LoweredTypeKind classifyType(CanType type, SILModule &M,
- CanGenericSignature sig,
- ResilienceExpansion expansion) {
+static RecursiveProperties classifyType(CanType type, SILModule &M,
+ CanGenericSignature sig,
+ ResilienceExpansion expansion) {
assert(!type->hasError() &&
"Error types should not appear in type-checked AST");
@@ -530,8 +528,7 @@
bool SILType::isAddressOnly(CanType type, SILModule &M,
CanGenericSignature sig,
ResilienceExpansion expansion) {
- return classifyType(type, M, sig, expansion)
- == LoweredTypeKind::AddressOnly;
+ return classifyType(type, M, sig, expansion).isAddressOnly();
}
namespace {
@@ -540,10 +537,9 @@
/// opaque values are passed by value.
class LoadableTypeLowering : public TypeLowering {
protected:
- LoadableTypeLowering(SILType type, IsTrivial_t isTrivial,
- IsAddressOnly_t isAddressOnly,
+ LoadableTypeLowering(SILType type, RecursiveProperties properties,
IsReferenceCounted_t isRefCounted)
- : TypeLowering(type, isTrivial, isAddressOnly, isRefCounted) {}
+ : TypeLowering(type, properties, isRefCounted) {}
public:
void emitDestroyAddress(SILBuilder &B, SILLocation loc,
@@ -565,11 +561,11 @@
}
};
- /// A class for trivial, loadable types.
+ /// A class for trivial, fixed-layout, loadable types.
class TrivialTypeLowering final : public LoadableTypeLowering {
public:
TrivialTypeLowering(SILType type)
- : LoadableTypeLowering(type, IsTrivial, IsNotAddressOnly,
+ : LoadableTypeLowering(type, {IsTrivial, IsFixedABI, IsNotAddressOnly},
IsNotReferenceCounted) {}
SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc, SILValue addr,
@@ -632,9 +628,18 @@
class NonTrivialLoadableTypeLowering : public LoadableTypeLowering {
public:
NonTrivialLoadableTypeLowering(SILType type,
- IsAddressOnly_t isAddressOnly,
IsReferenceCounted_t isRefCounted)
- : LoadableTypeLowering(type, IsNotTrivial, isAddressOnly, isRefCounted) {}
+ : NonTrivialLoadableTypeLowering(type,
+ {IsNotTrivial, IsFixedABI, IsNotAddressOnly},
+ isRefCounted) {}
+
+ /// This constructor is necessary because of opaque-values.
+ NonTrivialLoadableTypeLowering(SILType type,
+ RecursiveProperties properties,
+ IsReferenceCounted_t isRefCounted)
+ : LoadableTypeLowering(type, properties, isRefCounted) {
+ assert(!properties.isTrivial());
+ }
SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc,
SILValue addr, IsTake_t isTake) const override {
@@ -725,7 +730,6 @@
public:
LoadableAggTypeLowering(CanType type)
: NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type),
- IsNotAddressOnly,
IsNotReferenceCounted) {
}
@@ -910,7 +914,6 @@
public:
LoadableEnumTypeLowering(CanType type)
: NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type),
- IsNotAddressOnly,
IsNotReferenceCounted) {}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
@@ -948,10 +951,9 @@
class LeafLoadableTypeLowering : public NonTrivialLoadableTypeLowering {
public:
- LeafLoadableTypeLowering(SILType type,
- IsAddressOnly_t isAddressOnly,
+ LeafLoadableTypeLowering(SILType type, RecursiveProperties properties,
IsReferenceCounted_t isRefCounted)
- : NonTrivialLoadableTypeLowering(type, isAddressOnly, isRefCounted) {}
+ : NonTrivialLoadableTypeLowering(type, properties, isRefCounted) {}
SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
@@ -970,7 +972,8 @@
class ReferenceTypeLowering : public LeafLoadableTypeLowering {
public:
ReferenceTypeLowering(SILType type)
- : LeafLoadableTypeLowering(type, IsNotAddressOnly, IsReferenceCounted) {}
+ : LeafLoadableTypeLowering(type, RecursiveProperties::forReference(),
+ IsReferenceCounted) {}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
@@ -998,7 +1001,8 @@
class LoadableUnownedTypeLowering final : public LeafLoadableTypeLowering {
public:
LoadableUnownedTypeLowering(SILType type)
- : LeafLoadableTypeLowering(type, IsNotAddressOnly, IsReferenceCounted) {}
+ : LeafLoadableTypeLowering(type, RecursiveProperties::forReference(),
+ IsReferenceCounted) {}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
@@ -1022,8 +1026,8 @@
/// A class for non-trivial, address-only types.
class AddressOnlyTypeLowering : public TypeLowering {
public:
- AddressOnlyTypeLowering(SILType type)
- : TypeLowering(type, IsNotTrivial, IsAddressOnly, IsNotReferenceCounted)
+ AddressOnlyTypeLowering(SILType type, RecursiveProperties properties)
+ : TypeLowering(type, properties, IsNotReferenceCounted)
{}
void emitCopyInto(SILBuilder &B, SILLocation loc,
@@ -1055,12 +1059,14 @@
void emitDestroyAddress(SILBuilder &B, SILLocation loc,
SILValue addr) const override {
- B.emitDestroyAddrAndFold(loc, addr);
+ if (!isTrivial())
+ B.emitDestroyAddrAndFold(loc, addr);
}
void emitDestroyRValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
- B.emitDestroyAddrAndFold(loc, value);
+ if (!isTrivial())
+ B.emitDestroyAddrAndFold(loc, value);
}
SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
@@ -1090,7 +1096,8 @@
class UnsafeValueBufferTypeLowering : public AddressOnlyTypeLowering {
public:
UnsafeValueBufferTypeLowering(SILType type)
- : AddressOnlyTypeLowering(type) {}
+ : AddressOnlyTypeLowering(type,
+ {IsNotTrivial, IsFixedABI, IsAddressOnly}) {}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
@@ -1116,8 +1123,8 @@
/// FIXME: When you remove an unreachable, just delete the method.
class OpaqueValueTypeLowering : public LeafLoadableTypeLowering {
public:
- OpaqueValueTypeLowering(SILType type)
- : LeafLoadableTypeLowering(type, IsAddressOnly, IsNotReferenceCounted) {}
+ OpaqueValueTypeLowering(SILType type, RecursiveProperties properties)
+ : LeafLoadableTypeLowering(type, properties, IsNotReferenceCounted) {}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
@@ -1149,71 +1156,6 @@
}
};
- /// A class for trivial, address-only types.
- class AddressOnlyTrivialTypeLowering : public TypeLowering {
- public:
- AddressOnlyTrivialTypeLowering(SILType type)
- : TypeLowering(type, IsTrivial, IsAddressOnly, IsNotReferenceCounted)
- {}
-
- void emitCopyInto(SILBuilder &B, SILLocation loc,
- SILValue src, SILValue dest, IsTake_t isTake,
- IsInitialization_t isInit) const override {
- B.createCopyAddr(loc, src, dest, isTake, isInit);
- }
-
- SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc,
- SILValue addr, IsTake_t isTake) const override {
- llvm_unreachable("calling emitLoadOfCopy on non-loadable type");
- }
-
- void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
- SILValue newValue, SILValue addr,
- IsInitialization_t isInit) const override {
- llvm_unreachable("calling emitStoreOfCopy on non-loadable type");
- }
-
- void emitStore(SILBuilder &B, SILLocation loc, SILValue value,
- SILValue addr, StoreOwnershipQualifier qual) const override {
- llvm_unreachable("calling emitStore on non-loadable type");
- }
-
- SILValue emitLoad(SILBuilder &B, SILLocation loc, SILValue addr,
- LoadOwnershipQualifier qual) const override {
- llvm_unreachable("calling emitLoad on non-loadable type");
- }
-
- void emitDestroyAddress(SILBuilder &B, SILLocation loc,
- SILValue addr) const override {
- }
-
- void emitDestroyRValue(SILBuilder &B, SILLocation loc,
- SILValue value) const override {
- }
-
- SILValue emitCopyValue(SILBuilder &B, SILLocation loc,
- SILValue value) const override {
- llvm_unreachable("type is not loadable!");
- }
-
- SILValue emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
- SILValue value,
- TypeExpansionKind style) const override {
- llvm_unreachable("type is not loadable!");
- }
-
- void emitDestroyValue(SILBuilder &B, SILLocation loc,
- SILValue value) const override {
- llvm_unreachable("type is not loadable!");
- }
-
- void emitLoweredDestroyValue(SILBuilder &B, SILLocation loc, SILValue value,
- TypeExpansionKind style) const override {
- llvm_unreachable("type is not loadable!");
- }
- };
-
-
/// Build the appropriate TypeLowering subclass for the given type,
/// which is assumed to already have been lowered.
class LowerType
@@ -1233,24 +1175,19 @@
return new (TC, Dependent) TrivialTypeLowering(silType);
}
- const TypeLowering *
- handleTrivialAddressOnly(CanType type) {
- auto silType = SILType::getPrimitiveObjectType(type);
- return new (TC, Dependent) AddressOnlyTrivialTypeLowering(silType);
- }
-
const TypeLowering *handleReference(CanType type) {
auto silType = SILType::getPrimitiveObjectType(type);
return new (TC, Dependent) ReferenceTypeLowering(silType);
}
- const TypeLowering *handleAddressOnly(CanType type) {
+ const TypeLowering *handleAddressOnly(CanType type,
+ RecursiveProperties properties) {
if (SILModuleConventions(M).useLoweredAddresses()) {
auto silType = SILType::getPrimitiveAddressType(type);
- return new (TC, Dependent) AddressOnlyTypeLowering(silType);
+ return new (TC, Dependent) AddressOnlyTypeLowering(silType, properties);
}
auto silType = SILType::getPrimitiveObjectType(type);
- return new (TC, Dependent) OpaqueValueTypeLowering(silType);
+ return new (TC, Dependent) OpaqueValueTypeLowering(silType, properties);
}
const TypeLowering *
@@ -1266,19 +1203,14 @@
}
const TypeLowering *visitTupleType(CanTupleType tupleType) {
- bool hasOnlyTrivialChildren = true;
-
+ RecursiveProperties properties;
for (auto eltType : tupleType.getElementTypes()) {
auto &lowering = TC.getTypeLowering(eltType);
- if (lowering.isAddressOnly())
- return handleAddressOnly(tupleType);
- hasOnlyTrivialChildren &= lowering.isTrivial();
+ properties.addSubobject(lowering.getRecursiveProperties());
}
- if (hasOnlyTrivialChildren)
- return handleTrivial(tupleType);
-
- return new (TC, Dependent) LoadableTupleTypeLowering(tupleType);
+ return handleAggregateByProperties<LoadableTupleTypeLowering>(tupleType,
+ properties);
}
const TypeLowering *visitAnyStructType(CanType structType, StructDecl *D) {
@@ -1286,37 +1218,27 @@
// For now, if the type does not have a fixed layout in all resilience
// domains, we will treat it as address-only in SIL.
if (D->isResilient(M.getSwiftModule(), Expansion))
- return handleAddressOnly(structType);
+ return handleAddressOnly(structType,
+ RecursiveProperties::forOpaque());
// Classify the type according to its stored properties.
- bool trivial = true;
+ RecursiveProperties properties;
for (auto field : D->getStoredProperties()) {
auto substFieldType =
structType->getTypeOfMember(D->getModuleContext(), field, nullptr);
- switch (classifyType(substFieldType->getCanonicalType(),
- M, Sig, Expansion)) {
- case LoweredTypeKind::TrivialAddressOnly:
- case LoweredTypeKind::AddressOnly:
- return handleAddressOnly(structType);
- case LoweredTypeKind::AggWithReference:
- case LoweredTypeKind::Reference:
- trivial = false;
- break;
- case LoweredTypeKind::Trivial:
- break;
- }
+ properties.addSubobject(classifyType(substFieldType->getCanonicalType(),
+ M, Sig, Expansion));
}
- if (trivial)
- return handleTrivial(structType);
- return new (TC, Dependent) LoadableStructTypeLowering(structType);
+ return handleAggregateByProperties<LoadableStructTypeLowering>(structType,
+ properties);
}
const TypeLowering *visitAnyEnumType(CanType enumType, EnumDecl *D) {
// For now, if the type does not have a fixed layout in all resilience
// domains, we will treat it as address-only in SIL.
if (D->isResilient(M.getSwiftModule(), Expansion))
- return handleAddressOnly(enumType);
+ return handleAddressOnly(enumType, RecursiveProperties::forOpaque());
// If the whole enum is indirect, we lower it as if all payload
// cases were indirect. This means a fixed-layout indirect enum
@@ -1327,18 +1249,16 @@
return new (TC, Dependent) LoadableEnumTypeLowering(enumType);
}
- // If any of the enum elements have address-only data, the enum is
- // address-only.
- bool trivial = true;
+ // Accumulate the properties of all direct payloads.
+ RecursiveProperties properties;
for (auto elt : D->getAllElements()) {
- // No-payload elements do not affect address-only-ness.
+ // No-payload elements do not affect any recursive properties.
if (!elt->hasAssociatedValues())
continue;
- // Indirect elements make the type nontrivial, but don't affect
- // address-only-ness.
+ // Indirect elements only make the type nontrivial.
if (elt->isIndirect()) {
- trivial = false;
+ properties.setNonTrivial();
continue;
}
@@ -1347,22 +1267,24 @@
elt->getArgumentInterfaceType())
->getCanonicalType();
- switch (classifyType(substEltType, M, Sig, Expansion)) {
- case LoweredTypeKind::TrivialAddressOnly:
- case LoweredTypeKind::AddressOnly:
- return handleAddressOnly(enumType);
- case LoweredTypeKind::AggWithReference:
- case LoweredTypeKind::Reference:
- trivial = false;
- break;
- case LoweredTypeKind::Trivial:
- break;
- }
-
+ properties.addSubobject(classifyType(substEltType, M, Sig, Expansion));
}
- if (trivial)
- return handleTrivial(enumType);
- return new (TC, Dependent) LoadableEnumTypeLowering(enumType);
+
+ return handleAggregateByProperties<LoadableEnumTypeLowering>(enumType,
+ properties);
+ }
+
+ template <class LoadableLoweringClass>
+ const TypeLowering *handleAggregateByProperties(CanType type,
+ RecursiveProperties props) {
+ if (props.isAddressOnly()) {
+ return handleAddressOnly(type, props);
+ }
+ assert(props.isFixedABI());
+ if (props.isTrivial()) {
+ return handleTrivial(type);
+ }
+ return new (TC, Dependent) LoadableLoweringClass(type);
}
};
} // end anonymous namespace
diff --git a/test/IRGen/Inputs/OtherModule.swift b/test/IRGen/Inputs/OtherModule.swift
new file mode 100644
index 0000000..ef16b8f
--- /dev/null
+++ b/test/IRGen/Inputs/OtherModule.swift
@@ -0,0 +1,24 @@
+import resilient_struct
+
+public struct First {}
+public struct Second {
+ public let resilientData: Size
+}
+
+private enum PrivateEnum {
+ case first(First?)
+ case second(Second?)
+}
+
+public struct Foo {
+ private var _property = PrivateEnum.first(nil)
+}
+
+internal enum InternalEnum {
+ case first(First?)
+ case second(Second?)
+}
+
+public struct Bar {
+ private var _property = InternalEnum.first(nil)
+}
diff --git a/test/IRGen/multi_file_resilience.swift b/test/IRGen/multi_file_resilience.swift
new file mode 100644
index 0000000..02aef2c
--- /dev/null
+++ b/test/IRGen/multi_file_resilience.swift
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// RUN: %target-swift-frontend -emit-module -enable-resilience \
+// RUN: -emit-module-path=%t/resilient_struct.swiftmodule \
+// RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+
+// RUN: %target-swift-frontend -module-name main -I %t -emit-ir -primary-file %s %S/Inputs/OtherModule.swift | %FileCheck %s -DINT=i%target-ptrsize
+
+// This is a single-module version of the test case in
+// multi_module_resilience.
+// rdar://39763787
+
+// CHECK-LABEL: define {{(protected )?}}swiftcc void @"$S4main7copyFoo3fooAA0C0VAE_tF"
+// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$S4main3FooVMa"([[INT]] 0)
+// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
+// CHECK: [[VWT:%.*]] = load i8**,
+// Allocate 'copy'.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
+// CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
+// CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[FOO:%T4main3FooV]]*
+// Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[COPYFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
+// CHECK: [[DEST:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque*
+// CHECK: [[SRC:%.*]] = bitcast [[FOO]]* %1 to %swift.opaque*
+// CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]])
+// Perform 'initializeWithTake' via the VWT.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[TAKEFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
+// CHECK: [[DEST:%.*]] = bitcast [[FOO]]* %0 to %swift.opaque*
+// CHECK: [[SRC:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque*
+// CHECK: call %swift.opaque* [[TAKEFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]])
+public func copyFoo(foo: Foo) -> Foo {
+ let copy = foo
+ return copy
+}
diff --git a/test/IRGen/multi_module_resilience.swift b/test/IRGen/multi_module_resilience.swift
new file mode 100644
index 0000000..cfd146a
--- /dev/null
+++ b/test/IRGen/multi_module_resilience.swift
@@ -0,0 +1,74 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// RUN: %target-swift-frontend -emit-module -enable-resilience \
+// RUN: -emit-module-path=%t/resilient_struct.swiftmodule \
+// RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+
+// RUN: %target-swift-frontend -emit-module -I %t \
+// RUN: -emit-module-path=%t/OtherModule.swiftmodule \
+// RUN: -module-name=OtherModule %S/Inputs/OtherModule.swift
+
+// RUN: %target-swift-frontend -module-name main -I %t -emit-ir %s | %FileCheck %s -DINT=i%target-ptrsize
+
+// rdar://39763787
+
+import OtherModule
+
+// CHECK-LABEL: define {{(protected )?}}swiftcc void @"$S4main7copyFoo3foo11OtherModule0C0VAF_tF"
+// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$S11OtherModule3FooVMa"([[INT]] 0)
+// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
+// CHECK: [[VWT:%.*]] = load i8**,
+// Allocate 'copy'.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
+// CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
+// CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[FOO:%T11OtherModule3FooV]]*
+// Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[COPYFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
+// CHECK: [[DEST:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque*
+// CHECK: [[SRC:%.*]] = bitcast [[FOO]]* %1 to %swift.opaque*
+// CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]])
+// Perform 'initializeWithTake' via the VWT.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[TAKEFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
+// CHECK: [[DEST:%.*]] = bitcast [[FOO]]* %0 to %swift.opaque*
+// CHECK: [[SRC:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque*
+// CHECK: call %swift.opaque* [[TAKEFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]])
+public func copyFoo(foo: Foo) -> Foo {
+ let copy = foo
+ return copy
+}
+
+// CHECK-LABEL: define {{(protected )?}}swiftcc void @"$S4main7copyBar3bar11OtherModule0C0VAF_tF"
+// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$S11OtherModule3BarVMa"([[INT]] 0)
+// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
+// CHECK: [[VWT:%.*]] = load i8**,
+// Allocate 'copy'.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
+// CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
+// CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[BAR:%T11OtherModule3BarV]]*
+// Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[COPYFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
+// CHECK: [[DEST:%.*]] = bitcast [[BAR]]* [[COPY]] to %swift.opaque*
+// CHECK: [[SRC:%.*]] = bitcast [[BAR]]* %1 to %swift.opaque*
+// CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]])
+// Perform 'initializeWithTake' via the VWT.
+// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4
+// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
+// CHECK: [[TAKEFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
+// CHECK: [[DEST:%.*]] = bitcast [[BAR]]* %0 to %swift.opaque*
+// CHECK: [[SRC:%.*]] = bitcast [[BAR]]* [[COPY]] to %swift.opaque*
+// CHECK: call %swift.opaque* [[TAKEFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]])
+public func copyBar(bar: Bar) -> Bar {
+ let copy = bar
+ return copy
+}