mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -168,17 +168,18 @@ public:
|
|||||||
// flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
|
// flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
|
||||||
// still require additional fixup.)
|
// still require additional fixup.)
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
AlignmentMask = 0x000000FF,
|
AlignmentMask = 0x000000FF,
|
||||||
// unused 0x0000FF00,
|
// unused 0x0000FF00,
|
||||||
IsNonPOD = 0x00010000,
|
IsNonPOD = 0x00010000,
|
||||||
IsNonInline = 0x00020000,
|
IsNonInline = 0x00020000,
|
||||||
// unused 0x00040000,
|
// unused 0x00040000,
|
||||||
HasSpareBits = 0x00080000,
|
HasSpareBits = 0x00080000,
|
||||||
IsNonBitwiseTakable = 0x00100000,
|
IsNonBitwiseTakable = 0x00100000,
|
||||||
HasEnumWitnesses = 0x00200000,
|
HasEnumWitnesses = 0x00200000,
|
||||||
Incomplete = 0x00400000,
|
Incomplete = 0x00400000,
|
||||||
IsNonCopyable = 0x00800000,
|
IsNonCopyable = 0x00800000,
|
||||||
// unused 0xFF000000,
|
IsNonBitwiseBorrowable = 0x01000000,
|
||||||
|
// unused 0xFE000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
|
static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
|
||||||
@@ -243,6 +244,27 @@ public:
|
|||||||
(isBT ? 0 : IsNonBitwiseTakable));
|
(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.
|
/// True if values of this type can be copied.
|
||||||
bool isCopyable() const { return !(Data & IsNonCopyable); }
|
bool isCopyable() const { return !(Data & IsNonCopyable); }
|
||||||
constexpr TargetValueWitnessFlags withCopyable(bool isCopyable) const {
|
constexpr TargetValueWitnessFlags withCopyable(bool isCopyable) const {
|
||||||
|
|||||||
@@ -3927,8 +3927,8 @@ namespace {
|
|||||||
} else if (allSingleRefcount
|
} else if (allSingleRefcount
|
||||||
&& ElementsWithNoPayload.size() <= 1) {
|
&& ElementsWithNoPayload.size() <= 1) {
|
||||||
CopyDestroyKind = TaggedRefcounted;
|
CopyDestroyKind = TaggedRefcounted;
|
||||||
} else if (this->EnumImplStrategy::BitwiseTakable == IsBitwiseTakable &&
|
} else if (this->EnumImplStrategy::BitwiseTakable == IsBitwiseTakableAndBorrowable
|
||||||
Copyable == IsCopyable) {
|
&& Copyable == IsCopyable) {
|
||||||
CopyDestroyKind = BitwiseTakable;
|
CopyDestroyKind = BitwiseTakable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6396,7 +6396,7 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
|
|||||||
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
||||||
auto copyable = !theEnum->canBeCopyable()
|
auto copyable = !theEnum->canBeCopyable()
|
||||||
? IsNotCopyable : IsCopyable;
|
? IsNotCopyable : IsCopyable;
|
||||||
auto bitwiseTakable = IsBitwiseTakable; // FIXME: will there be check here?
|
auto bitwiseTakable = IsBitwiseTakableAndBorrowable; // FIXME: will there be check here?
|
||||||
bool allowFixedLayoutOptimizations = true;
|
bool allowFixedLayoutOptimizations = true;
|
||||||
std::vector<Element> elementsWithPayload;
|
std::vector<Element> elementsWithPayload;
|
||||||
std::vector<Element> elementsWithNoPayload;
|
std::vector<Element> elementsWithNoPayload;
|
||||||
@@ -6408,7 +6408,7 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
|
|||||||
payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
||||||
copyable = copyable & payloadTI.isCopyable(ResilienceExpansion::Maximal);
|
copyable = copyable & payloadTI.isCopyable(ResilienceExpansion::Maximal);
|
||||||
bitwiseTakable = bitwiseTakable &
|
bitwiseTakable = bitwiseTakable &
|
||||||
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal);
|
payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (TC.IGM.isResilient(theEnum, ResilienceExpansion::Minimal))
|
if (TC.IGM.isResilient(theEnum, ResilienceExpansion::Minimal))
|
||||||
@@ -6861,7 +6861,8 @@ EnumImplStrategy::getFixedEnumTypeInfo(llvm::StructType *T, Size S,
|
|||||||
abiAccessible);
|
abiAccessible);
|
||||||
break;
|
break;
|
||||||
case Loadable:
|
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,
|
mutableTI = new LoadableEnumTypeInfo(*this, T, S, std::move(SB), A,
|
||||||
isTriviallyDestroyable,
|
isTriviallyDestroyable,
|
||||||
isCopyable,
|
isCopyable,
|
||||||
@@ -7084,7 +7085,7 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout(
|
|||||||
getFixedEnumTypeInfo(
|
getFixedEnumTypeInfo(
|
||||||
enumTy, Size(sizeWithTag), spareBits.build(), alignment,
|
enumTy, Size(sizeWithTag), spareBits.build(), alignment,
|
||||||
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
|
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
|
||||||
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal),
|
payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal),
|
||||||
copyable, isABIAccessible);
|
copyable, isABIAccessible);
|
||||||
|
|
||||||
if (TIK >= Loadable && CopyDestroyKind == Normal) {
|
if (TIK >= Loadable && CopyDestroyKind == Normal) {
|
||||||
@@ -7120,7 +7121,7 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeDynamicLayout(
|
|||||||
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
|
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
|
||||||
alignment,
|
alignment,
|
||||||
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
|
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
|
||||||
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal),
|
payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal),
|
||||||
copyable,
|
copyable,
|
||||||
enumAccessible));
|
enumAccessible));
|
||||||
}
|
}
|
||||||
@@ -7155,7 +7156,7 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
|
|||||||
? IsNotCopyable : IsCopyable;
|
? IsNotCopyable : IsCopyable;
|
||||||
auto isTriviallyDestroyable = theEnum->getValueTypeDestructor()
|
auto isTriviallyDestroyable = theEnum->getValueTypeDestructor()
|
||||||
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
||||||
IsBitwiseTakable_t isBT = IsBitwiseTakable;
|
IsBitwiseTakable_t isBT = IsBitwiseTakableAndBorrowable;
|
||||||
PayloadSize = 0;
|
PayloadSize = 0;
|
||||||
for (auto &elt : ElementsWithPayload) {
|
for (auto &elt : ElementsWithPayload) {
|
||||||
auto &fixedPayloadTI = cast<FixedTypeInfo>(*elt.ti);
|
auto &fixedPayloadTI = cast<FixedTypeInfo>(*elt.ti);
|
||||||
@@ -7163,8 +7164,7 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
|
|||||||
worstAlignment = fixedPayloadTI.getFixedAlignment();
|
worstAlignment = fixedPayloadTI.getFixedAlignment();
|
||||||
if (!fixedPayloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal))
|
if (!fixedPayloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal))
|
||||||
isTriviallyDestroyable = IsNotTriviallyDestroyable;
|
isTriviallyDestroyable = IsNotTriviallyDestroyable;
|
||||||
if (!fixedPayloadTI.isBitwiseTakable(ResilienceExpansion::Maximal))
|
isBT &= fixedPayloadTI.getBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
isBT = IsNotBitwiseTakable;
|
|
||||||
|
|
||||||
unsigned payloadBytes = fixedPayloadTI.getFixedSize().getValue();
|
unsigned payloadBytes = fixedPayloadTI.getFixedSize().getValue();
|
||||||
unsigned payloadBits = fixedPayloadTI.getFixedSize().getValueInBits();
|
unsigned payloadBits = fixedPayloadTI.getFixedSize().getValueInBits();
|
||||||
@@ -7324,12 +7324,12 @@ TypeInfo *MultiPayloadEnumImplStrategy::completeDynamicLayout(
|
|||||||
Alignment alignment(1);
|
Alignment alignment(1);
|
||||||
auto td = theEnum->getValueTypeDestructor()
|
auto td = theEnum->getValueTypeDestructor()
|
||||||
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
||||||
auto bt = IsBitwiseTakable;
|
auto bt = IsBitwiseTakableAndBorrowable;
|
||||||
for (auto &element : ElementsWithPayload) {
|
for (auto &element : ElementsWithPayload) {
|
||||||
auto &payloadTI = *element.ti;
|
auto &payloadTI = *element.ti;
|
||||||
alignment = std::max(alignment, payloadTI.getBestKnownAlignment());
|
alignment = std::max(alignment, payloadTI.getBestKnownAlignment());
|
||||||
td &= payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
td &= payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
||||||
bt &= payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal);
|
bt &= payloadTI.getBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyLayoutAttributes(TC.IGM, theEnum, /*fixed*/false, alignment);
|
applyLayoutAttributes(TC.IGM, theEnum, /*fixed*/false, alignment);
|
||||||
|
|||||||
@@ -900,11 +900,16 @@ class OpaqueExistentialTypeInfo final :
|
|||||||
|
|
||||||
OpaqueExistentialTypeInfo(ArrayRef<const ProtocolDecl *> protocols,
|
OpaqueExistentialTypeInfo(ArrayRef<const ProtocolDecl *> protocols,
|
||||||
llvm::Type *ty, Size size,
|
llvm::Type *ty, Size size,
|
||||||
|
IsCopyable_t copyable,
|
||||||
SpareBitVector &&spareBits,
|
SpareBitVector &&spareBits,
|
||||||
Alignment align)
|
Alignment align)
|
||||||
: super(protocols, ty, size,
|
: super(protocols, ty, size,
|
||||||
std::move(spareBits), align,
|
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) {}
|
IsFixedSize, IsABIAccessible) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -1649,14 +1654,19 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
|
|||||||
OpaqueExistentialLayout opaque(protosWithWitnessTables.size());
|
OpaqueExistentialLayout opaque(protosWithWitnessTables.size());
|
||||||
Alignment align = opaque.getAlignment(IGM);
|
Alignment align = opaque.getAlignment(IGM);
|
||||||
Size size = opaque.getSize(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
|
// There are spare bits in the metadata pointer and witness table pointers
|
||||||
// consistent with a native object reference.
|
// consistent with a native object reference.
|
||||||
// TODO: There are spare bits we could theoretically use in the type metadata
|
// NB: There are spare bits we could theoretically use in the type metadata
|
||||||
// and witness table pointers, but opaque existentials are currently address-
|
// and witness table pointers, but opaque existentials are address-
|
||||||
// only, and we can't soundly take advantage of spare bits for in-memory
|
// only, and we can't soundly take advantage of spare bits for in-memory
|
||||||
// representations.
|
// representations.
|
||||||
|
// Maybe an ABI break that made opaque existentials loadable could use those
|
||||||
|
// bits, though.
|
||||||
auto spareBits = SpareBitVector::getConstant(size.getValueInBits(), false);
|
auto spareBits = SpareBitVector::getConstant(size.getValueInBits(), false);
|
||||||
return OpaqueExistentialTypeInfo::create(protosWithWitnessTables, type, size,
|
return OpaqueExistentialTypeInfo::create(protosWithWitnessTables, type, size,
|
||||||
|
copyable,
|
||||||
std::move(spareBits),
|
std::move(spareBits),
|
||||||
align);
|
align);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -579,7 +579,7 @@ const TypeInfo *TypeConverter::convertBlockStorageType(SILBlockStorageType *T) {
|
|||||||
|
|
||||||
size = captureOffset + fixedCapture->getFixedSize();
|
size = captureOffset + fixedCapture->getFixedSize();
|
||||||
pod = fixedCapture->isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
pod = fixedCapture->isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
||||||
bt = fixedCapture->isBitwiseTakable(ResilienceExpansion::Maximal);
|
bt = fixedCapture->getBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Type *storageElts[] = {
|
llvm::Type *storageElts[] = {
|
||||||
|
|||||||
@@ -1144,7 +1144,7 @@ public:
|
|||||||
|
|
||||||
auto alignment = ti->getFixedAlignment().getValue();
|
auto alignment = ti->getFixedAlignment().getValue();
|
||||||
unsigned bitwiseTakable =
|
unsigned bitwiseTakable =
|
||||||
(ti->isBitwiseTakable(ResilienceExpansion::Minimal) == IsBitwiseTakable
|
(ti->getBitwiseTakable(ResilienceExpansion::Minimal) >= IsBitwiseTakableOnly
|
||||||
? 1 : 0);
|
? 1 : 0);
|
||||||
B.addInt32(alignment | (bitwiseTakable << 16));
|
B.addInt32(alignment | (bitwiseTakable << 16));
|
||||||
|
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ llvm::Value *FixedTypeInfo::getIsTriviallyDestroyable(IRGenFunction &IGF, SILTyp
|
|||||||
}
|
}
|
||||||
llvm::Value *FixedTypeInfo::getIsBitwiseTakable(IRGenFunction &IGF, SILType T) const {
|
llvm::Value *FixedTypeInfo::getIsBitwiseTakable(IRGenFunction &IGF, SILType T) const {
|
||||||
return llvm::ConstantInt::get(IGF.IGM.Int1Ty,
|
return llvm::ConstantInt::get(IGF.IGM.Int1Ty,
|
||||||
isBitwiseTakable(ResilienceExpansion::Maximal) == IsBitwiseTakable);
|
getBitwiseTakable(ResilienceExpansion::Maximal) >= IsBitwiseTakableOnly);
|
||||||
}
|
}
|
||||||
llvm::Constant *FixedTypeInfo::getStaticStride(IRGenModule &IGM) const {
|
llvm::Constant *FixedTypeInfo::getStaticStride(IRGenModule &IGM) const {
|
||||||
return IGM.getSize(getFixedStride());
|
return IGM.getSize(getFixedStride());
|
||||||
|
|||||||
@@ -849,12 +849,22 @@ ValueWitnessFlags getValueWitnessFlags(const TypeInfo *TI, SILType concreteType,
|
|||||||
bool isInline = packing == FixedPacking::OffsetZero;
|
bool isInline = packing == FixedPacking::OffsetZero;
|
||||||
bool isBitwiseTakable =
|
bool isBitwiseTakable =
|
||||||
fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal);
|
fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
|
bool isBitwiseBorrowable =
|
||||||
|
fixedTI->isBitwiseBorrowable(ResilienceExpansion::Maximal);
|
||||||
assert(isBitwiseTakable || !isInline);
|
assert(isBitwiseTakable || !isInline);
|
||||||
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
|
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
|
||||||
.withPOD(fixedTI->isTriviallyDestroyable(ResilienceExpansion::Maximal))
|
.withPOD(fixedTI->isTriviallyDestroyable(ResilienceExpansion::Maximal))
|
||||||
.withCopyable(fixedTI->isCopyable(ResilienceExpansion::Maximal))
|
.withCopyable(fixedTI->isCopyable(ResilienceExpansion::Maximal))
|
||||||
.withInlineStorage(isInline)
|
.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 {
|
} else {
|
||||||
flags = flags.withIncomplete(true);
|
flags = flags.withIncomplete(true);
|
||||||
}
|
}
|
||||||
@@ -1532,12 +1542,12 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
|
|||||||
unsigned align = ti.getFixedAlignment().getValue();
|
unsigned align = ti.getFixedAlignment().getValue();
|
||||||
|
|
||||||
bool pod = ti.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
bool pod = ti.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
||||||
bool bt = ti.isBitwiseTakable(ResilienceExpansion::Maximal);
|
IsBitwiseTakable_t bt = ti.getBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
unsigned numExtraInhabitants = ti.getFixedExtraInhabitantCount(*this);
|
unsigned numExtraInhabitants = ti.getFixedExtraInhabitantCount(*this);
|
||||||
|
|
||||||
// Try to use common type layouts exported by the runtime.
|
// Try to use common type layouts exported by the runtime.
|
||||||
llvm::Constant *commonValueWitnessTable = nullptr;
|
llvm::Constant *commonValueWitnessTable = nullptr;
|
||||||
if (pod && bt && numExtraInhabitants == 0) {
|
if (pod && bt == IsBitwiseTakableAndBorrowable && numExtraInhabitants == 0) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
commonValueWitnessTable =
|
commonValueWitnessTable =
|
||||||
getAddrOfValueWitnessTable(Context.TheEmptyTupleType);
|
getAddrOfValueWitnessTable(Context.TheEmptyTupleType);
|
||||||
@@ -1562,7 +1572,7 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
|
|||||||
|
|
||||||
// Otherwise, see if a layout has been emitted with these characteristics
|
// Otherwise, see if a layout has been emitted with these characteristics
|
||||||
// already.
|
// already.
|
||||||
FixedLayoutKey key{size, numExtraInhabitants, align, pod, bt};
|
FixedLayoutKey key{size, numExtraInhabitants, align, pod, unsigned(bt)};
|
||||||
|
|
||||||
auto found = PrivateFixedLayouts.find(key);
|
auto found = PrivateFixedLayouts.find(key);
|
||||||
if (found != PrivateFixedLayouts.end())
|
if (found != PrivateFixedLayouts.end())
|
||||||
@@ -1578,16 +1588,29 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,
|
|||||||
addValueWitness(*this, witnesses, witness, packing, t, silTy, ti);
|
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
|
auto layoutVar
|
||||||
= witnesses.finishAndCreateGlobal(
|
= witnesses.finishAndCreateGlobal(
|
||||||
"type_layout_" + llvm::Twine(size)
|
"type_layout_" + llvm::Twine(size)
|
||||||
+ "_" + llvm::Twine(align)
|
+ "_" + llvm::Twine(align)
|
||||||
+ "_" + llvm::Twine::utohexstr(numExtraInhabitants)
|
+ "_" + llvm::Twine::utohexstr(numExtraInhabitants)
|
||||||
+ (pod ? "_pod" :
|
+ pod_bt_string(pod, bt),
|
||||||
bt ? "_bt" : ""),
|
getPointerAlignment(),
|
||||||
getPointerAlignment(),
|
/*constant*/ true,
|
||||||
/*constant*/ true,
|
llvm::GlobalValue::PrivateLinkage);
|
||||||
llvm::GlobalValue::PrivateLinkage);
|
|
||||||
|
|
||||||
// Cast to the standard currency type for type layouts.
|
// Cast to the standard currency type for type layouts.
|
||||||
auto layout = llvm::ConstantExpr::getBitCast(layoutVar, Int8PtrPtrTy);
|
auto layout = llvm::ConstantExpr::getBitCast(layoutVar, Int8PtrPtrTy);
|
||||||
|
|||||||
@@ -80,9 +80,15 @@ inline IsLoadable_t &operator&=(IsLoadable_t &l, IsLoadable_t r) {
|
|||||||
return (l = (l & 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) {
|
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) {
|
inline IsBitwiseTakable_t &operator&=(IsBitwiseTakable_t &l, IsBitwiseTakable_t r) {
|
||||||
return (l = (l & r));
|
return (l = (l & r));
|
||||||
|
|||||||
@@ -1368,7 +1368,7 @@ private:
|
|||||||
unsigned numExtraInhabitants;
|
unsigned numExtraInhabitants;
|
||||||
unsigned align: 16;
|
unsigned align: 16;
|
||||||
unsigned pod: 1;
|
unsigned pod: 1;
|
||||||
unsigned bitwiseTakable: 1;
|
unsigned bitwiseTakable: 2;
|
||||||
};
|
};
|
||||||
friend struct ::llvm::DenseMapInfo<swift::irgen::IRGenModule::FixedLayoutKey>;
|
friend struct ::llvm::DenseMapInfo<swift::irgen::IRGenModule::FixedLayoutKey>;
|
||||||
llvm::DenseMap<FixedLayoutKey, llvm::Constant *> PrivateFixedLayouts;
|
llvm::DenseMap<FixedLayoutKey, llvm::Constant *> PrivateFixedLayouts;
|
||||||
|
|||||||
@@ -65,8 +65,9 @@ protected:
|
|||||||
IsABIAccessible_t isABIAccessible,
|
IsABIAccessible_t isABIAccessible,
|
||||||
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
|
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
|
||||||
: FixedTypeInfo(type, size, spareBits, align, pod,
|
: FixedTypeInfo(type, size, spareBits, align, pod,
|
||||||
// All currently implemented loadable types are bitwise-takable.
|
// All currently implemented loadable types are
|
||||||
IsBitwiseTakable,
|
// bitwise-takable and -borrowable.
|
||||||
|
IsBitwiseTakableAndBorrowable,
|
||||||
copy, alwaysFixedSize, isABIAccessible, stik) {
|
copy, alwaysFixedSize, isABIAccessible, stik) {
|
||||||
assert(isLoadable());
|
assert(isLoadable());
|
||||||
}
|
}
|
||||||
@@ -80,8 +81,9 @@ protected:
|
|||||||
IsABIAccessible_t isABIAccessible,
|
IsABIAccessible_t isABIAccessible,
|
||||||
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
|
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
|
||||||
: FixedTypeInfo(type, size, std::move(spareBits), align, pod,
|
: FixedTypeInfo(type, size, std::move(spareBits), align, pod,
|
||||||
// All currently implemented loadable types are bitwise-takable.
|
// All currently implemented loadable types are
|
||||||
IsBitwiseTakable,
|
// bitwise-takable and borrowable.
|
||||||
|
IsBitwiseTakableAndBorrowable,
|
||||||
copy, alwaysFixedSize, isABIAccessible, stik) {
|
copy, alwaysFixedSize, isABIAccessible, stik) {
|
||||||
assert(isLoadable());
|
assert(isLoadable());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
|
|||||||
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
||||||
auto copyable = (decl && !decl->canBeCopyable())
|
auto copyable = (decl && !decl->canBeCopyable())
|
||||||
? IsNotCopyable : IsCopyable;
|
? IsNotCopyable : IsCopyable;
|
||||||
IsBitwiseTakable_t bitwiseTakable = IsBitwiseTakable;
|
IsBitwiseTakable_t bitwiseTakable = IsBitwiseTakableAndBorrowable;
|
||||||
|
|
||||||
if (decl && decl->getAttrs().hasAttribute<SensitiveAttr>()) {
|
if (decl && decl->getAttrs().hasAttribute<SensitiveAttr>()) {
|
||||||
triviallyDestroyable = IsNotTriviallyDestroyable;
|
triviallyDestroyable = IsNotTriviallyDestroyable;
|
||||||
@@ -87,7 +87,8 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
|
|||||||
if (rawLayout && type) {
|
if (rawLayout && type) {
|
||||||
auto sd = cast<StructDecl>(decl);
|
auto sd = cast<StructDecl>(decl);
|
||||||
IsKnownTriviallyDestroyable = triviallyDestroyable;
|
IsKnownTriviallyDestroyable = triviallyDestroyable;
|
||||||
IsKnownBitwiseTakable = bitwiseTakable;
|
// Raw layout types are never bitwise-borrowable.
|
||||||
|
IsKnownBitwiseTakable = bitwiseTakable & IsBitwiseTakableOnly;
|
||||||
SpareBits.clear();
|
SpareBits.clear();
|
||||||
assert(!copyable);
|
assert(!copyable);
|
||||||
IsKnownCopyable = copyable;
|
IsKnownCopyable = copyable;
|
||||||
@@ -168,7 +169,9 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
|
|||||||
// type its like.
|
// type its like.
|
||||||
if (rawLayout->shouldMoveAsLikeType()) {
|
if (rawLayout->shouldMoveAsLikeType()) {
|
||||||
IsKnownTriviallyDestroyable = likeFixedType->isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
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 {
|
} else {
|
||||||
MinimumSize = Size(0);
|
MinimumSize = Size(0);
|
||||||
@@ -417,7 +420,7 @@ bool StructLayoutBuilder::addField(ElementLayout &elt,
|
|||||||
LayoutStrategy strategy) {
|
LayoutStrategy strategy) {
|
||||||
auto &eltTI = elt.getType();
|
auto &eltTI = elt.getType();
|
||||||
IsKnownTriviallyDestroyable &= eltTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
IsKnownTriviallyDestroyable &= eltTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
|
||||||
IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceExpansion::Maximal);
|
IsKnownBitwiseTakable &= eltTI.getBitwiseTakable(ResilienceExpansion::Maximal);
|
||||||
IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal);
|
IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal);
|
||||||
IsLoadable &= eltTI.isLoadable();
|
IsLoadable &= eltTI.isLoadable();
|
||||||
IsKnownCopyable &= eltTI.isCopyable(ResilienceExpansion::Maximal);
|
IsKnownCopyable &= eltTI.isCopyable(ResilienceExpansion::Maximal);
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ private:
|
|||||||
bool IsFixedLayout = true;
|
bool IsFixedLayout = true;
|
||||||
bool IsLoadable = true;
|
bool IsLoadable = true;
|
||||||
IsTriviallyDestroyable_t IsKnownTriviallyDestroyable = IsTriviallyDestroyable;
|
IsTriviallyDestroyable_t IsKnownTriviallyDestroyable = IsTriviallyDestroyable;
|
||||||
IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakable;
|
IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakableAndBorrowable;
|
||||||
IsCopyable_t IsKnownCopyable = IsCopyable;
|
IsCopyable_t IsKnownCopyable = IsCopyable;
|
||||||
IsFixedSize_t IsKnownAlwaysFixedSize = IsFixedSize;
|
IsFixedSize_t IsKnownAlwaysFixedSize = IsFixedSize;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ protected:
|
|||||||
uint64_t OpaqueBits;
|
uint64_t OpaqueBits;
|
||||||
|
|
||||||
SWIFT_INLINE_BITFIELD_BASE(TypeInfo,
|
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.
|
/// The kind of supplemental API this type has, if any.
|
||||||
Kind : bitmax(NumSpecialTypeInfoKindBits,8),
|
Kind : bitmax(NumSpecialTypeInfoKindBits,8),
|
||||||
|
|
||||||
@@ -114,6 +114,9 @@ protected:
|
|||||||
/// Whether this type is known to be bitwise-takable.
|
/// Whether this type is known to be bitwise-takable.
|
||||||
BitwiseTakable : 1,
|
BitwiseTakable : 1,
|
||||||
|
|
||||||
|
/// Whether this type is known to be bitwise-borrowable.
|
||||||
|
BitwiseBorrowable : 1,
|
||||||
|
|
||||||
/// Whether this type is known to be copyable.
|
/// Whether this type is known to be copyable.
|
||||||
Copyable : 1,
|
Copyable : 1,
|
||||||
|
|
||||||
@@ -160,7 +163,9 @@ protected:
|
|||||||
Bits.TypeInfo.Kind = unsigned(stik);
|
Bits.TypeInfo.Kind = unsigned(stik);
|
||||||
Bits.TypeInfo.AlignmentShift = llvm::Log2_32(A.getValue());
|
Bits.TypeInfo.AlignmentShift = llvm::Log2_32(A.getValue());
|
||||||
Bits.TypeInfo.TriviallyDestroyable = pod;
|
Bits.TypeInfo.TriviallyDestroyable = pod;
|
||||||
Bits.TypeInfo.BitwiseTakable = bitwiseTakable;
|
Bits.TypeInfo.BitwiseTakable = bitwiseTakable >= IsBitwiseTakableOnly;
|
||||||
|
Bits.TypeInfo.BitwiseBorrowable =
|
||||||
|
bitwiseTakable == IsBitwiseTakableAndBorrowable;
|
||||||
Bits.TypeInfo.Copyable = copyable;
|
Bits.TypeInfo.Copyable = copyable;
|
||||||
Bits.TypeInfo.SubclassKind = InvalidSubclassKind;
|
Bits.TypeInfo.SubclassKind = InvalidSubclassKind;
|
||||||
Bits.TypeInfo.AlwaysFixedSize = alwaysFixedSize;
|
Bits.TypeInfo.AlwaysFixedSize = alwaysFixedSize;
|
||||||
@@ -231,11 +236,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this type is known to be bitwise-takable, i.e. "initializeWithTake"
|
/// Whether this type is known to be bitwise-takable, i.e. "initializeWithTake"
|
||||||
/// is equivalent to a memcpy.
|
/// is equivalent to a memcpy, and possibly bitwise-borrowable, i.e.,
|
||||||
IsBitwiseTakable_t isBitwiseTakable(ResilienceExpansion expansion) const {
|
/// a borrowed argument can be passed by value rather than by reference.
|
||||||
return IsBitwiseTakable_t(Bits.TypeInfo.BitwiseTakable);
|
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.
|
/// Returns the type of special interface followed by this TypeInfo.
|
||||||
/// It is important for our design that this depends only on
|
/// It is important for our design that this depends only on
|
||||||
/// immediate type structure and not on, say, properties that can
|
/// immediate type structure and not on, say, properties that can
|
||||||
|
|||||||
38
test/IRGen/existential-bitwise-borrowability.swift
Normal file
38
test/IRGen/existential-bitwise-borrowability.swift
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ import RawLayoutCXX
|
|||||||
// CHECK-SAME: , {{i64|i32}} 4
|
// CHECK-SAME: , {{i64|i32}} 4
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 4
|
// CHECK-SAME: , {{i64|i32}} 4
|
||||||
// flags: alignment 3, noncopyable
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
|
|
||||||
@_rawLayout(size: 4, alignment: 4)
|
@_rawLayout(size: 4, alignment: 4)
|
||||||
struct Lock: ~Copyable { }
|
struct Lock: ~Copyable { }
|
||||||
@@ -27,8 +27,8 @@ struct PaddedStride {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 5
|
// CHECK-SAME: , {{i64|i32}} 5
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// flags: alignment 3, noncopyable
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
@_rawLayout(like: PaddedStride)
|
@_rawLayout(like: PaddedStride)
|
||||||
struct LikePaddedStride: ~Copyable {}
|
struct LikePaddedStride: ~Copyable {}
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ struct LikePaddedStride: ~Copyable {}
|
|||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// flags: alignment 3, noncopyable
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
@_rawLayout(likeArrayOf: PaddedStride, count: 1)
|
@_rawLayout(likeArrayOf: PaddedStride, count: 1)
|
||||||
struct LikePaddedStrideArray1: ~Copyable {}
|
struct LikePaddedStrideArray1: ~Copyable {}
|
||||||
|
|
||||||
@@ -47,9 +47,9 @@ struct LikePaddedStrideArray1: ~Copyable {}
|
|||||||
// CHECK-SAME: , {{i64|i32}} 16
|
// CHECK-SAME: , {{i64|i32}} 16
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 16
|
// CHECK-SAME: , {{i64|i32}} 16
|
||||||
// flags: alignment 3, noncopyable, (on 32-bit platforms) not storable inline
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable, (on 32-bit platforms) not storable inline
|
||||||
// CHECK-64-SAME: , <i32 0x800003>
|
// CHECK-64-SAME: , <i32 0x1800003>
|
||||||
// CHECK-32-SAME: , <i32 0x820003>
|
// CHECK-32-SAME: , <i32 0x1820003>
|
||||||
@_rawLayout(likeArrayOf: PaddedStride, count: 2)
|
@_rawLayout(likeArrayOf: PaddedStride, count: 2)
|
||||||
struct LikePaddedStrideArray2: ~Copyable {}
|
struct LikePaddedStrideArray2: ~Copyable {}
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ struct LikePaddedStrideArray2: ~Copyable {}
|
|||||||
// CHECK-SAME: , {{i64|i32}} 12
|
// CHECK-SAME: , {{i64|i32}} 12
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 12
|
// CHECK-SAME: , {{i64|i32}} 12
|
||||||
// flags: alignment 3, noncopyable
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
struct Keymaster: ~Copyable {
|
struct Keymaster: ~Copyable {
|
||||||
let lock1: Lock
|
let lock1: Lock
|
||||||
let lock2: Lock
|
let lock2: Lock
|
||||||
@@ -125,8 +125,8 @@ struct Vector<T, let N: Int>: ~Copyable {}
|
|||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// flags: alignment 3, noncopyable
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
struct UsesCell: ~Copyable {
|
struct UsesCell: ~Copyable {
|
||||||
let someCondition: Bool
|
let someCondition: Bool
|
||||||
let specialInt: Cell<Int32>
|
let specialInt: Cell<Int32>
|
||||||
@@ -137,8 +137,8 @@ struct UsesCell: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 3
|
// CHECK-SAME: , {{i64|i32}} 3
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 3
|
// CHECK-SAME: , {{i64|i32}} 3
|
||||||
// flags: alignment 0, noncopyable
|
// flags: alignment 0, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800000>
|
// CHECK-SAME: , <i32 0x1800000>
|
||||||
struct BufferOf3Bool: ~Copyable {
|
struct BufferOf3Bool: ~Copyable {
|
||||||
let buffer: SmallVectorOf3<Bool>
|
let buffer: SmallVectorOf3<Bool>
|
||||||
}
|
}
|
||||||
@@ -148,8 +148,8 @@ struct BufferOf3Bool: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 48
|
// CHECK-SAME: , {{i64|i32}} 48
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 48
|
// CHECK-SAME: , {{i64|i32}} 48
|
||||||
// flags: alignment 7, noncopyable, is not inline
|
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
|
||||||
// CHECK-SAME: , <i32 0x820007>
|
// CHECK-SAME: , <i32 0x1820007>
|
||||||
struct BadBuffer: ~Copyable {
|
struct BadBuffer: ~Copyable {
|
||||||
let buffer: SmallVectorOf3<Int64?>
|
let buffer: SmallVectorOf3<Int64?>
|
||||||
}
|
}
|
||||||
@@ -159,8 +159,8 @@ struct BadBuffer: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 2
|
// CHECK-SAME: , {{i64|i32}} 2
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 2
|
// CHECK-SAME: , {{i64|i32}} 2
|
||||||
// flags: alignment 0, noncopyable
|
// flags: alignment 0, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800000>
|
// CHECK-SAME: , <i32 0x1800000>
|
||||||
struct UsesVector: ~Copyable {
|
struct UsesVector: ~Copyable {
|
||||||
let buffer: Vector<UInt8, 2>
|
let buffer: Vector<UInt8, 2>
|
||||||
}
|
}
|
||||||
@@ -170,8 +170,8 @@ struct UsesVector: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 48
|
// CHECK-SAME: , {{i64|i32}} 48
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 48
|
// CHECK-SAME: , {{i64|i32}} 48
|
||||||
// flags: alignment 7, noncopyable, is not inline
|
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
|
||||||
// CHECK-SAME: , <i32 0x820007>
|
// CHECK-SAME: , <i32 0x1820007>
|
||||||
struct BadBuffer2: ~Copyable {
|
struct BadBuffer2: ~Copyable {
|
||||||
let buffer: Vector<Int64?, 3>
|
let buffer: Vector<Int64?, 3>
|
||||||
}
|
}
|
||||||
@@ -222,8 +222,8 @@ struct ConcreteMoveAsLike: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 4
|
// CHECK-SAME: , {{i64|i32}} 4
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 4
|
// CHECK-SAME: , {{i64|i32}} 4
|
||||||
// flags: alignment 3, not copyable
|
// flags: alignment 3, not copyable, not bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
struct ConcreteIntMoveAsLike: ~Copyable {
|
struct ConcreteIntMoveAsLike: ~Copyable {
|
||||||
let cell: CellThatMovesAsLike<Int32>
|
let cell: CellThatMovesAsLike<Int32>
|
||||||
}
|
}
|
||||||
@@ -272,8 +272,8 @@ struct ConcreteSmallVectorMovesAsLike: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// flags: alignment 3, not copyable
|
// flags: alignment 3, not copyable, not bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
struct ConcreteSmallVectorIntMovesAsLike: ~Copyable {
|
struct ConcreteSmallVectorIntMovesAsLike: ~Copyable {
|
||||||
let vector: SmallVectorOf2MovesAsLike<Int32>
|
let vector: SmallVectorOf2MovesAsLike<Int32>
|
||||||
}
|
}
|
||||||
@@ -322,9 +322,9 @@ struct ConcreteVectorMovesAsLike: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 16
|
// CHECK-SAME: , {{i64|i32}} 16
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 16
|
// CHECK-SAME: , {{i64|i32}} 16
|
||||||
// flags: alignment 3, not copyable, (on 32-bit platforms) not storable inline
|
// flags: alignment 3, not copyable, not bitwise-borrowable, (on 32-bit platforms) not storable inline
|
||||||
// CHECK-64-SAME: , <i32 0x800003>
|
// CHECK-64-SAME: , <i32 0x1800003>
|
||||||
// CHECK-32-SAME: , <i32 0x820003>
|
// CHECK-32-SAME: , <i32 0x1820003>
|
||||||
struct ConcreteVectorIntMovesAsLike: ~Copyable {
|
struct ConcreteVectorIntMovesAsLike: ~Copyable {
|
||||||
let vector: VectorMovesAsLike<Int32, 4>
|
let vector: VectorMovesAsLike<Int32, 4>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ public struct Foo<T>: ~Copyable {}
|
|||||||
// CHECK-SAME: , {{i64|i32}} 4
|
// CHECK-SAME: , {{i64|i32}} 4
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 4
|
// CHECK-SAME: , {{i64|i32}} 4
|
||||||
// flags: alignment 3, noncopyable
|
// flags: alignment 3, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME: , <i32 0x800003>
|
// CHECK-SAME: , <i32 0x1800003>
|
||||||
struct MyInt: ~Copyable {
|
struct MyInt: ~Copyable {
|
||||||
let x: Int32Fake
|
let x: Int32Fake
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,8 @@ struct MyInt: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 48
|
// CHECK-SAME: , {{i64|i32}} 48
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 48
|
// CHECK-SAME: , {{i64|i32}} 48
|
||||||
// flags: alignment 7, noncopyable, is not inline
|
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
|
||||||
// CHECK-SAME: , <i32 0x820007>
|
// CHECK-SAME: , <i32 0x1820007>
|
||||||
struct BadBuffer: ~Copyable {
|
struct BadBuffer: ~Copyable {
|
||||||
let buf = SmallVectorOf3<Int64?>()
|
let buf = SmallVectorOf3<Int64?>()
|
||||||
}
|
}
|
||||||
@@ -32,10 +32,10 @@ struct BadBuffer: ~Copyable {
|
|||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// stride
|
// stride
|
||||||
// CHECK-SAME: , {{i64|i32}} 8
|
// CHECK-SAME: , {{i64|i32}} 8
|
||||||
// flags-32: alignment 7, noncopyable, is not inline
|
// flags-32: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
|
||||||
// CHECK-SAME-32: , <i32 0x820007>
|
// CHECK-SAME-32: , <i32 0x1820007>
|
||||||
// flags-64: alignment 7, noncopyable
|
// flags-64: alignment 7, noncopyable, non-bitwise-borrowable
|
||||||
// CHECK-SAME-64: , <i32 0x800007>
|
// CHECK-SAME-64: , <i32 0x1800007>
|
||||||
struct Weird: ~Copyable {
|
struct Weird: ~Copyable {
|
||||||
let value = UnsafeCell<Int64>()
|
let value = UnsafeCell<Int64>()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user