IRGen: Set a "not bitwise borrowable" bit in value witnesses for @_rawLayout types.

For types like `Atomic` and `Mutex`, we want to know that even though they are
technically bitwise-takable, they differ from other bitwise-takable types until
this point because they are not also "bitwise-borrowable"; while borrowed,
they are pinned in memory, so they cannot be passed by value as a borrowed
parameter, unlike copyable bitwise-takable types. Add a bit to the value witness
table flags to record this.

Note that this patch does not include any accompanying runtime support for
propagating the flag into runtime-instantiated type metadata. There isn't yet
any runtime functionality that varies based on this flag, so that can
be implemented separately.

rdar://136396806
This commit is contained in:
Joe Groff
2024-09-23 18:14:45 -07:00
parent ada0ceb2d9
commit 57a56e5804
16 changed files with 214 additions and 91 deletions

View File

@@ -168,17 +168,18 @@ public:
// flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
// still require additional fixup.)
enum : uint32_t {
AlignmentMask = 0x000000FF,
// unused 0x0000FF00,
IsNonPOD = 0x00010000,
IsNonInline = 0x00020000,
// unused 0x00040000,
HasSpareBits = 0x00080000,
IsNonBitwiseTakable = 0x00100000,
HasEnumWitnesses = 0x00200000,
Incomplete = 0x00400000,
IsNonCopyable = 0x00800000,
// unused 0xFF000000,
AlignmentMask = 0x000000FF,
// unused 0x0000FF00,
IsNonPOD = 0x00010000,
IsNonInline = 0x00020000,
// unused 0x00040000,
HasSpareBits = 0x00080000,
IsNonBitwiseTakable = 0x00100000,
HasEnumWitnesses = 0x00200000,
Incomplete = 0x00400000,
IsNonCopyable = 0x00800000,
IsNonBitwiseBorrowable = 0x01000000,
// unused 0xFE000000,
};
static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
@@ -243,6 +244,27 @@ public:
(isBT ? 0 : IsNonBitwiseTakable));
}
/// True if values of this type can be passed by value when borrowed.
/// If this bit is true, then borrows of the value are independent of the
/// value's address, so a value can be passed in registers or memcpy'd
/// while borrowed. This is in contrast to Rust, for instance, where a
/// `&T` type is always represented as a pointer, and borrowing a
/// value always moves the borrowed value into memory.
bool isBitwiseBorrowable() const {
/// This bit was introduced with Swift 6; prior to the introduction of
/// `Atomic` and `Mutex`, a type was always bitwise-borrowable if it
/// was bitwise-takable. Compilers and runtimes before Swift 6 would
/// never set the `IsNonBitwiseBorrowable` bit in the value witness
/// table, but any type that sets `IsNonBitwiseTakable` is definitely
/// not bitwise borrowable.
return isBitwiseTakable()
&& !(Data & IsNonBitwiseBorrowable);
}
constexpr TargetValueWitnessFlags withBitwiseBorrowable(bool isBB) const {
return TargetValueWitnessFlags((Data & ~IsNonBitwiseBorrowable) |
(isBB ? 0 : IsNonBitwiseBorrowable));
}
/// True if values of this type can be copied.
bool isCopyable() const { return !(Data & IsNonCopyable); }
constexpr TargetValueWitnessFlags withCopyable(bool isCopyable) const {

View File

@@ -3927,8 +3927,8 @@ namespace {
} else if (allSingleRefcount
&& ElementsWithNoPayload.size() <= 1) {
CopyDestroyKind = TaggedRefcounted;
} else if (this->EnumImplStrategy::BitwiseTakable == IsBitwiseTakable &&
Copyable == IsCopyable) {
} else if (this->EnumImplStrategy::BitwiseTakable == IsBitwiseTakableAndBorrowable
&& Copyable == IsCopyable) {
CopyDestroyKind = BitwiseTakable;
}
}
@@ -6396,7 +6396,7 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
auto copyable = !theEnum->canBeCopyable()
? IsNotCopyable : IsCopyable;
auto bitwiseTakable = IsBitwiseTakable; // FIXME: will there be check here?
auto bitwiseTakable = IsBitwiseTakableAndBorrowable; // FIXME: will there be check here?
bool allowFixedLayoutOptimizations = true;
std::vector<Element> elementsWithPayload;
std::vector<Element> elementsWithNoPayload;
@@ -6408,7 +6408,7 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
copyable = copyable & payloadTI.isCopyable(ResilienceExpansion::Maximal);
bitwiseTakable = bitwiseTakable &
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal);
payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal);
};
if (TC.IGM.isResilient(theEnum, ResilienceExpansion::Minimal))
@@ -6861,7 +6861,8 @@ EnumImplStrategy::getFixedEnumTypeInfo(llvm::StructType *T, Size S,
abiAccessible);
break;
case Loadable:
assert(isBT && "loadable enum not bitwise takable?!");
assert(isBT == IsBitwiseTakableAndBorrowable
&& "loadable enum not bitwise takable?!");
mutableTI = new LoadableEnumTypeInfo(*this, T, S, std::move(SB), A,
isTriviallyDestroyable,
isCopyable,
@@ -7084,7 +7085,7 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout(
getFixedEnumTypeInfo(
enumTy, Size(sizeWithTag), spareBits.build(), alignment,
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal),
payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal),
copyable, isABIAccessible);
if (TIK >= Loadable && CopyDestroyKind == Normal) {
@@ -7120,7 +7121,7 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeDynamicLayout(
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
alignment,
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal),
payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal),
copyable,
enumAccessible));
}
@@ -7155,7 +7156,7 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
? IsNotCopyable : IsCopyable;
auto isTriviallyDestroyable = theEnum->getValueTypeDestructor()
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
IsBitwiseTakable_t isBT = IsBitwiseTakable;
IsBitwiseTakable_t isBT = IsBitwiseTakableAndBorrowable;
PayloadSize = 0;
for (auto &elt : ElementsWithPayload) {
auto &fixedPayloadTI = cast<FixedTypeInfo>(*elt.ti);
@@ -7163,8 +7164,7 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
worstAlignment = fixedPayloadTI.getFixedAlignment();
if (!fixedPayloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal))
isTriviallyDestroyable = IsNotTriviallyDestroyable;
if (!fixedPayloadTI.isBitwiseTakable(ResilienceExpansion::Maximal))
isBT = IsNotBitwiseTakable;
isBT &= fixedPayloadTI.getBitwiseTakable(ResilienceExpansion::Maximal);
unsigned payloadBytes = fixedPayloadTI.getFixedSize().getValue();
unsigned payloadBits = fixedPayloadTI.getFixedSize().getValueInBits();
@@ -7324,12 +7324,12 @@ TypeInfo *MultiPayloadEnumImplStrategy::completeDynamicLayout(
Alignment alignment(1);
auto td = theEnum->getValueTypeDestructor()
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
auto bt = IsBitwiseTakable;
auto bt = IsBitwiseTakableAndBorrowable;
for (auto &element : ElementsWithPayload) {
auto &payloadTI = *element.ti;
alignment = std::max(alignment, payloadTI.getBestKnownAlignment());
td &= payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
bt &= payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal);
bt &= payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal);
}
applyLayoutAttributes(TC.IGM, theEnum, /*fixed*/false, alignment);

View File

@@ -900,11 +900,16 @@ class OpaqueExistentialTypeInfo final :
OpaqueExistentialTypeInfo(ArrayRef<const ProtocolDecl *> protocols,
llvm::Type *ty, Size size,
IsCopyable_t copyable,
SpareBitVector &&spareBits,
Alignment align)
: super(protocols, ty, size,
std::move(spareBits), align,
IsNotTriviallyDestroyable, IsBitwiseTakable, IsCopyable,
IsNotTriviallyDestroyable,
// Copyable existentials are bitwise-takable and borrowable.
// Noncopyable existentials are bitwise-takable only.
copyable ? IsBitwiseTakableAndBorrowable : IsBitwiseTakableOnly,
copyable,
IsFixedSize, IsABIAccessible) {}
public:
@@ -1649,14 +1654,19 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
OpaqueExistentialLayout opaque(protosWithWitnessTables.size());
Alignment align = opaque.getAlignment(IGM);
Size size = opaque.getSize(IGM);
IsCopyable_t copyable = T->isNoncopyable() ? IsNotCopyable : IsCopyable;
// There are spare bits in the metadata pointer and witness table pointers
// consistent with a native object reference.
// TODO: There are spare bits we could theoretically use in the type metadata
// and witness table pointers, but opaque existentials are currently address-
// NB: There are spare bits we could theoretically use in the type metadata
// and witness table pointers, but opaque existentials are address-
// only, and we can't soundly take advantage of spare bits for in-memory
// representations.
// Maybe an ABI break that made opaque existentials loadable could use those
// bits, though.
auto spareBits = SpareBitVector::getConstant(size.getValueInBits(), false);
return OpaqueExistentialTypeInfo::create(protosWithWitnessTables, type, size,
copyable,
std::move(spareBits),
align);
}

View File

@@ -579,7 +579,7 @@ const TypeInfo *TypeConverter::convertBlockStorageType(SILBlockStorageType *T) {
size = captureOffset + fixedCapture->getFixedSize();
pod = fixedCapture->isTriviallyDestroyable(ResilienceExpansion::Maximal);
bt = fixedCapture->isBitwiseTakable(ResilienceExpansion::Maximal);
bt = fixedCapture->getBitwiseTakable(ResilienceExpansion::Maximal);
}
llvm::Type *storageElts[] = {

View File

@@ -1144,7 +1144,7 @@ public:
auto alignment = ti->getFixedAlignment().getValue();
unsigned bitwiseTakable =
(ti->isBitwiseTakable(ResilienceExpansion::Minimal) == IsBitwiseTakable
(ti->getBitwiseTakable(ResilienceExpansion::Minimal) >= IsBitwiseTakableOnly
? 1 : 0);
B.addInt32(alignment | (bitwiseTakable << 16));

View File

@@ -236,7 +236,7 @@ llvm::Value *FixedTypeInfo::getIsTriviallyDestroyable(IRGenFunction &IGF, SILTyp
}
llvm::Value *FixedTypeInfo::getIsBitwiseTakable(IRGenFunction &IGF, SILType T) const {
return llvm::ConstantInt::get(IGF.IGM.Int1Ty,
isBitwiseTakable(ResilienceExpansion::Maximal) == IsBitwiseTakable);
getBitwiseTakable(ResilienceExpansion::Maximal) >= IsBitwiseTakableOnly);
}
llvm::Constant *FixedTypeInfo::getStaticStride(IRGenModule &IGM) const {
return IGM.getSize(getFixedStride());

View File

@@ -849,12 +849,22 @@ ValueWitnessFlags getValueWitnessFlags(const TypeInfo *TI, SILType concreteType,
bool isInline = packing == FixedPacking::OffsetZero;
bool isBitwiseTakable =
fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal);
bool isBitwiseBorrowable =
fixedTI->isBitwiseBorrowable(ResilienceExpansion::Maximal);
assert(isBitwiseTakable || !isInline);
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
.withPOD(fixedTI->isTriviallyDestroyable(ResilienceExpansion::Maximal))
.withCopyable(fixedTI->isCopyable(ResilienceExpansion::Maximal))
.withInlineStorage(isInline)
.withBitwiseTakable(isBitwiseTakable);
.withBitwiseTakable(isBitwiseTakable)
// the IsNotBitwiseBorrowable bit only needs to be set if the
// type is bitwise-takable but not bitwise-borrowable, since
// a type must be bitwise-takable to be bitwise-borrowable.
//
// Swift prior to version 6 didn't have the
// IsNotBitwiseBorrowable bit, so to avoid unnecessary variation
// in metadata output, we only set the bit when needed.
.withBitwiseBorrowable(!isBitwiseTakable || isBitwiseBorrowable);
} else {
flags = flags.withIncomplete(true);
}
@@ -1532,12 +1542,12 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
unsigned align = ti.getFixedAlignment().getValue();
bool pod = ti.isTriviallyDestroyable(ResilienceExpansion::Maximal);
bool bt = ti.isBitwiseTakable(ResilienceExpansion::Maximal);
IsBitwiseTakable_t bt = ti.getBitwiseTakable(ResilienceExpansion::Maximal);
unsigned numExtraInhabitants = ti.getFixedExtraInhabitantCount(*this);
// Try to use common type layouts exported by the runtime.
llvm::Constant *commonValueWitnessTable = nullptr;
if (pod && bt && numExtraInhabitants == 0) {
if (pod && bt == IsBitwiseTakableAndBorrowable && numExtraInhabitants == 0) {
if (size == 0)
commonValueWitnessTable =
getAddrOfValueWitnessTable(Context.TheEmptyTupleType);
@@ -1562,7 +1572,7 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
// Otherwise, see if a layout has been emitted with these characteristics
// already.
FixedLayoutKey key{size, numExtraInhabitants, align, pod, bt};
FixedLayoutKey key{size, numExtraInhabitants, align, pod, unsigned(bt)};
auto found = PrivateFixedLayouts.find(key);
if (found != PrivateFixedLayouts.end())
@@ -1578,16 +1588,29 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
addValueWitness(*this, witnesses, witness, packing, t, silTy, ti);
}
auto pod_bt_string = [](bool pod, IsBitwiseTakable_t bt) -> StringRef {
if (pod) {
return "_pod";
}
switch (bt) {
case IsNotBitwiseTakable:
return "";
case IsBitwiseTakableOnly:
return "_bt_nbb";
case IsBitwiseTakableAndBorrowable:
return "_bt";
}
};
auto layoutVar
= witnesses.finishAndCreateGlobal(
"type_layout_" + llvm::Twine(size)
+ "_" + llvm::Twine(align)
+ "_" + llvm::Twine::utohexstr(numExtraInhabitants)
+ (pod ? "_pod" :
bt ? "_bt" : ""),
getPointerAlignment(),
/*constant*/ true,
llvm::GlobalValue::PrivateLinkage);
+ pod_bt_string(pod, bt),
getPointerAlignment(),
/*constant*/ true,
llvm::GlobalValue::PrivateLinkage);
// Cast to the standard currency type for type layouts.
auto layout = llvm::ConstantExpr::getBitCast(layoutVar, Int8PtrPtrTy);

View File

@@ -80,9 +80,15 @@ inline IsLoadable_t &operator&=(IsLoadable_t &l, IsLoadable_t r) {
return (l = (l & r));
}
enum IsBitwiseTakable_t : bool { IsNotBitwiseTakable, IsBitwiseTakable };
enum IsBitwiseTakable_t : uint8_t {
IsNotBitwiseTakable = 0,
// The type is bitwise-takable, but borrows are pinned to memory.
IsBitwiseTakableOnly = 1,
// The type is bitwise-takable and -borrowable.
IsBitwiseTakableAndBorrowable = 3,
};
inline IsBitwiseTakable_t operator&(IsBitwiseTakable_t l, IsBitwiseTakable_t r) {
return IsBitwiseTakable_t(unsigned(l) & unsigned(r));
return IsBitwiseTakable_t(std::min(unsigned(l), unsigned(r)));
}
inline IsBitwiseTakable_t &operator&=(IsBitwiseTakable_t &l, IsBitwiseTakable_t r) {
return (l = (l & r));

View File

@@ -1368,7 +1368,7 @@ private:
unsigned numExtraInhabitants;
unsigned align: 16;
unsigned pod: 1;
unsigned bitwiseTakable: 1;
unsigned bitwiseTakable: 2;
};
friend struct ::llvm::DenseMapInfo<swift::irgen::IRGenModule::FixedLayoutKey>;
llvm::DenseMap<FixedLayoutKey, llvm::Constant *> PrivateFixedLayouts;

View File

@@ -65,8 +65,9 @@ protected:
IsABIAccessible_t isABIAccessible,
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
: FixedTypeInfo(type, size, spareBits, align, pod,
// All currently implemented loadable types are bitwise-takable.
IsBitwiseTakable,
// All currently implemented loadable types are
// bitwise-takable and -borrowable.
IsBitwiseTakableAndBorrowable,
copy, alwaysFixedSize, isABIAccessible, stik) {
assert(isLoadable());
}
@@ -80,8 +81,9 @@ protected:
IsABIAccessible_t isABIAccessible,
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
: FixedTypeInfo(type, size, std::move(spareBits), align, pod,
// All currently implemented loadable types are bitwise-takable.
IsBitwiseTakable,
// All currently implemented loadable types are
// bitwise-takable and borrowable.
IsBitwiseTakableAndBorrowable,
copy, alwaysFixedSize, isABIAccessible, stik) {
assert(isLoadable());
}

View File

@@ -72,7 +72,7 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
auto copyable = (decl && !decl->canBeCopyable())
? IsNotCopyable : IsCopyable;
IsBitwiseTakable_t bitwiseTakable = IsBitwiseTakable;
IsBitwiseTakable_t bitwiseTakable = IsBitwiseTakableAndBorrowable;
if (decl && decl->getAttrs().hasAttribute<SensitiveAttr>()) {
triviallyDestroyable = IsNotTriviallyDestroyable;
@@ -87,7 +87,8 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
if (rawLayout && type) {
auto sd = cast<StructDecl>(decl);
IsKnownTriviallyDestroyable = triviallyDestroyable;
IsKnownBitwiseTakable = bitwiseTakable;
// Raw layout types are never bitwise-borrowable.
IsKnownBitwiseTakable = bitwiseTakable & IsBitwiseTakableOnly;
SpareBits.clear();
assert(!copyable);
IsKnownCopyable = copyable;
@@ -168,7 +169,9 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
// type its like.
if (rawLayout->shouldMoveAsLikeType()) {
IsKnownTriviallyDestroyable = likeFixedType->isTriviallyDestroyable(ResilienceExpansion::Maximal);
IsKnownBitwiseTakable = likeFixedType->isBitwiseTakable(ResilienceExpansion::Maximal);
// Raw layout types are still never bitwise-borrowable.
IsKnownBitwiseTakable = likeFixedType->getBitwiseTakable(ResilienceExpansion::Maximal)
& IsBitwiseTakableOnly;
}
} else {
MinimumSize = Size(0);
@@ -417,7 +420,7 @@ bool StructLayoutBuilder::addField(ElementLayout &elt,
LayoutStrategy strategy) {
auto &eltTI = elt.getType();
IsKnownTriviallyDestroyable &= eltTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceExpansion::Maximal);
IsKnownBitwiseTakable &= eltTI.getBitwiseTakable(ResilienceExpansion::Maximal);
IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal);
IsLoadable &= eltTI.isLoadable();
IsKnownCopyable &= eltTI.isCopyable(ResilienceExpansion::Maximal);

View File

@@ -285,7 +285,7 @@ private:
bool IsFixedLayout = true;
bool IsLoadable = true;
IsTriviallyDestroyable_t IsKnownTriviallyDestroyable = IsTriviallyDestroyable;
IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakable;
IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakableAndBorrowable;
IsCopyable_t IsKnownCopyable = IsCopyable;
IsFixedSize_t IsKnownAlwaysFixedSize = IsFixedSize;
public:

View File

@@ -101,7 +101,7 @@ protected:
uint64_t OpaqueBits;
SWIFT_INLINE_BITFIELD_BASE(TypeInfo,
bitmax(NumSpecialTypeInfoKindBits,8)+6+1+1+1+3+1+1,
bitmax(NumSpecialTypeInfoKindBits,8)+6+1+1+1+1+3+1+1,
/// The kind of supplemental API this type has, if any.
Kind : bitmax(NumSpecialTypeInfoKindBits,8),
@@ -114,6 +114,9 @@ protected:
/// Whether this type is known to be bitwise-takable.
BitwiseTakable : 1,
/// Whether this type is known to be bitwise-borrowable.
BitwiseBorrowable : 1,
/// Whether this type is known to be copyable.
Copyable : 1,
@@ -160,7 +163,9 @@ protected:
Bits.TypeInfo.Kind = unsigned(stik);
Bits.TypeInfo.AlignmentShift = llvm::Log2_32(A.getValue());
Bits.TypeInfo.TriviallyDestroyable = pod;
Bits.TypeInfo.BitwiseTakable = bitwiseTakable;
Bits.TypeInfo.BitwiseTakable = bitwiseTakable >= IsBitwiseTakableOnly;
Bits.TypeInfo.BitwiseBorrowable =
bitwiseTakable == IsBitwiseTakableAndBorrowable;
Bits.TypeInfo.Copyable = copyable;
Bits.TypeInfo.SubclassKind = InvalidSubclassKind;
Bits.TypeInfo.AlwaysFixedSize = alwaysFixedSize;
@@ -231,11 +236,25 @@ public:
}
/// Whether this type is known to be bitwise-takable, i.e. "initializeWithTake"
/// is equivalent to a memcpy.
IsBitwiseTakable_t isBitwiseTakable(ResilienceExpansion expansion) const {
return IsBitwiseTakable_t(Bits.TypeInfo.BitwiseTakable);
/// is equivalent to a memcpy, and possibly bitwise-borrowable, i.e.,
/// a borrowed argument can be passed by value rather than by reference.
IsBitwiseTakable_t getBitwiseTakable(ResilienceExpansion expansion) const {
return IsBitwiseTakable_t(
Bits.TypeInfo.BitwiseTakable | (Bits.TypeInfo.BitwiseBorrowable << 1));
}
/// Whether this type is known to be bitwise-takable, i.e. "initializeWithTake"
/// is equivalent to a memcpy
bool isBitwiseTakable(ResilienceExpansion expansion) const {
return Bits.TypeInfo.BitwiseTakable;
}
/// Whether this type is known to be bitwise-borrowable, i.e.,
/// a borrowed argument can be passed by value rather than by reference.
bool isBitwiseBorrowable(ResilienceExpansion expansion) const {
return Bits.TypeInfo.BitwiseBorrowable;
}
/// Returns the type of special interface followed by this TypeInfo.
/// It is important for our design that this depends only on
/// immediate type structure and not on, say, properties that can

View File

@@ -0,0 +1,38 @@
// RUN: %empty-directory(%t)
// RUN: %{python} %utils/chex.py < %s > %t/existential-bitwise-borrowability.swift
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -enable-experimental-feature ValueGenerics -emit-ir -disable-availability-checking -I %S/Inputs -cxx-interoperability-mode=upcoming-swift %t/existential-bitwise-borrowability.swift | %FileCheck %t/existential-bitwise-borrowability.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
// Copyable existentials are bitwise-borrowable (because copyable types are
// always bitwise-borrowable if they're bitwise-takable, and only bitwise-takable
// values are stored inline in existentials). Noncopyable existentials are
// not (since types like Atomic and Mutex can be stored inline in their
// buffers).
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}3FooVWV" = {{.*}} %swift.vwtable
// size
// CHECK-64-SAME: , {{i64|i32}} 32
// CHECK-32-SAME: , {{i64|i32}} 16
// stride
// CHECK-64-SAME: , {{i64|i32}} 32
// CHECK-32-SAME: , {{i64|i32}} 16
// flags: word alignment, noncopyable, non-POD, non-inline-storage
// CHECK-64-SAME: , <i32 0x830007>
// CHECK-32-SAME: , <i32 0x830003>
struct Foo: ~Copyable {
var x: Any
}
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}3BarVWV" = {{.*}} %swift.vwtable
// size
// CHECK-64-SAME: , {{i64|i32}} 32
// CHECK-32-SAME: , {{i64|i32}} 16
// stride
// CHECK-64-SAME: , {{i64|i32}} 32
// CHECK-32-SAME: , {{i64|i32}} 16
// flags: word alignment, non-bitwise-borrowable, noncopyable, non-POD, non-inline-storage
// CHECK-64-SAME: , <i32 0x1830007>
// CHECK-32-SAME: , <i32 0x1830003>
struct Bar: ~Copyable {
var x: any ~Copyable
}

View File

@@ -11,8 +11,8 @@ import RawLayoutCXX
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: alignment 3, noncopyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
@_rawLayout(size: 4, alignment: 4)
struct Lock: ~Copyable { }
@@ -27,8 +27,8 @@ struct PaddedStride {
// CHECK-SAME: , {{i64|i32}} 5
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, noncopyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
@_rawLayout(like: PaddedStride)
struct LikePaddedStride: ~Copyable {}
@@ -37,8 +37,8 @@ struct LikePaddedStride: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, noncopyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
@_rawLayout(likeArrayOf: PaddedStride, count: 1)
struct LikePaddedStrideArray1: ~Copyable {}
@@ -47,9 +47,9 @@ struct LikePaddedStrideArray1: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 16
// stride
// CHECK-SAME: , {{i64|i32}} 16
// flags: alignment 3, noncopyable, (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x800003>
// CHECK-32-SAME: , <i32 0x820003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x1800003>
// CHECK-32-SAME: , <i32 0x1820003>
@_rawLayout(likeArrayOf: PaddedStride, count: 2)
struct LikePaddedStrideArray2: ~Copyable {}
@@ -58,8 +58,8 @@ struct LikePaddedStrideArray2: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 12
// stride
// CHECK-SAME: , {{i64|i32}} 12
// flags: alignment 3, noncopyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
struct Keymaster: ~Copyable {
let lock1: Lock
let lock2: Lock
@@ -125,8 +125,8 @@ struct Vector<T, let N: Int>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, noncopyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
struct UsesCell: ~Copyable {
let someCondition: Bool
let specialInt: Cell<Int32>
@@ -137,8 +137,8 @@ struct UsesCell: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 3
// stride
// CHECK-SAME: , {{i64|i32}} 3
// flags: alignment 0, noncopyable
// CHECK-SAME: , <i32 0x800000>
// flags: alignment 0, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800000>
struct BufferOf3Bool: ~Copyable {
let buffer: SmallVectorOf3<Bool>
}
@@ -148,8 +148,8 @@ struct BufferOf3Bool: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 48
// stride
// CHECK-SAME: , {{i64|i32}} 48
// flags: alignment 7, noncopyable, is not inline
// CHECK-SAME: , <i32 0x820007>
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME: , <i32 0x1820007>
struct BadBuffer: ~Copyable {
let buffer: SmallVectorOf3<Int64?>
}
@@ -159,8 +159,8 @@ struct BadBuffer: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 2
// stride
// CHECK-SAME: , {{i64|i32}} 2
// flags: alignment 0, noncopyable
// CHECK-SAME: , <i32 0x800000>
// flags: alignment 0, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800000>
struct UsesVector: ~Copyable {
let buffer: Vector<UInt8, 2>
}
@@ -170,8 +170,8 @@ struct UsesVector: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 48
// stride
// CHECK-SAME: , {{i64|i32}} 48
// flags: alignment 7, noncopyable, is not inline
// CHECK-SAME: , <i32 0x820007>
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME: , <i32 0x1820007>
struct BadBuffer2: ~Copyable {
let buffer: Vector<Int64?, 3>
}
@@ -222,8 +222,8 @@ struct ConcreteMoveAsLike: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: alignment 3, not copyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, not copyable, not bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
struct ConcreteIntMoveAsLike: ~Copyable {
let cell: CellThatMovesAsLike<Int32>
}
@@ -272,8 +272,8 @@ struct ConcreteSmallVectorMovesAsLike: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, not copyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, not copyable, not bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
struct ConcreteSmallVectorIntMovesAsLike: ~Copyable {
let vector: SmallVectorOf2MovesAsLike<Int32>
}
@@ -322,9 +322,9 @@ struct ConcreteVectorMovesAsLike: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 16
// stride
// CHECK-SAME: , {{i64|i32}} 16
// flags: alignment 3, not copyable, (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x800003>
// CHECK-32-SAME: , <i32 0x820003>
// flags: alignment 3, not copyable, not bitwise-borrowable, (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x1800003>
// CHECK-32-SAME: , <i32 0x1820003>
struct ConcreteVectorIntMovesAsLike: ~Copyable {
let vector: VectorMovesAsLike<Int32, 4>
}

View File

@@ -10,8 +10,8 @@ public struct Foo<T>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: alignment 3, noncopyable
// CHECK-SAME: , <i32 0x800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
struct MyInt: ~Copyable {
let x: Int32Fake
}
@@ -21,8 +21,8 @@ struct MyInt: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 48
// stride
// CHECK-SAME: , {{i64|i32}} 48
// flags: alignment 7, noncopyable, is not inline
// CHECK-SAME: , <i32 0x820007>
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME: , <i32 0x1820007>
struct BadBuffer: ~Copyable {
let buf = SmallVectorOf3<Int64?>()
}
@@ -32,10 +32,10 @@ struct BadBuffer: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags-32: alignment 7, noncopyable, is not inline
// CHECK-SAME-32: , <i32 0x820007>
// flags-64: alignment 7, noncopyable
// CHECK-SAME-64: , <i32 0x800007>
// flags-32: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME-32: , <i32 0x1820007>
// flags-64: alignment 7, noncopyable, non-bitwise-borrowable
// CHECK-SAME-64: , <i32 0x1800007>
struct Weird: ~Copyable {
let value = UnsafeCell<Int64>()
}