Add an "addressable for dependencies" flag to value witness flags.

This may be useful for type layout of borrow fields in the future, should we
decide that addressable-for-dependencies borrows should always be represented
by a pointer. rdar://153650278
This commit is contained in:
Joe Groff
2025-06-17 14:51:26 -07:00
parent d242750ac9
commit 009ce4b82a
6 changed files with 116 additions and 61 deletions

View File

@@ -165,18 +165,19 @@ 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,
IsNonBitwiseBorrowable = 0x01000000,
// unused 0xFE000000,
AlignmentMask = 0x000000FF,
// unused 0x0000FF00,
IsNonPOD = 0x00010000,
IsNonInline = 0x00020000,
// unused 0x00040000,
HasSpareBits = 0x00080000,
IsNonBitwiseTakable = 0x00100000,
HasEnumWitnesses = 0x00200000,
Incomplete = 0x00400000,
IsNonCopyable = 0x00800000,
IsNonBitwiseBorrowable = 0x01000000,
IsAddressableForDependencies = 0x02000000,
// unused 0xFC000000,
};
static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
@@ -268,6 +269,19 @@ public:
return TargetValueWitnessFlags((Data & ~IsNonCopyable) |
(isCopyable ? 0 : IsNonCopyable));
}
/// True if values of this type are addressable-for-dependencies, meaning
/// that values of this type should be passed indirectly to functions that
/// produce lifetime-dependent values that could possibly contain pointers
/// to the inline storage of this type.
bool isAddressableForDependencies() const {
return Data & IsAddressableForDependencies;
}
constexpr TargetValueWitnessFlags withAddressableForDependencies(bool afd) const {
return TargetValueWitnessFlags((Data & ~IsAddressableForDependencies) |
(afd ? IsAddressableForDependencies : 0));
}
/// True if this type's binary representation is that of an enum, and the
/// enum value witness table entries are available in this type's value

View File

@@ -837,7 +837,9 @@ struct BoundGenericTypeCharacteristics {
FixedPacking packing;
};
ValueWitnessFlags getValueWitnessFlags(const TypeInfo *TI, SILType concreteType,
ValueWitnessFlags getValueWitnessFlags(IRGenModule &IGM,
const TypeInfo *TI,
SILType concreteType,
FixedPacking packing) {
ValueWitnessFlags flags;
@@ -852,6 +854,12 @@ ValueWitnessFlags getValueWitnessFlags(const TypeInfo *TI, SILType concreteType,
bool isBitwiseBorrowable =
fixedTI->isBitwiseBorrowable(ResilienceExpansion::Maximal);
assert(isBitwiseTakable || !isInline);
bool isAddressableForDependencies =
IGM.getSILModule().Types.getTypeLowering(concreteType,
TypeExpansionContext::minimal())
.getRecursiveProperties()
.isAddressableForDependencies();
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
.withPOD(fixedTI->isTriviallyDestroyable(ResilienceExpansion::Maximal))
.withCopyable(fixedTI->isCopyable(ResilienceExpansion::Maximal))
@@ -864,7 +872,8 @@ ValueWitnessFlags getValueWitnessFlags(const TypeInfo *TI, SILType concreteType,
// 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);
.withBitwiseBorrowable(!isBitwiseTakable || isBitwiseBorrowable)
.withAddressableForDependencies(isAddressableForDependencies);
} else {
flags = flags.withIncomplete(true);
}
@@ -1226,11 +1235,13 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
case ValueWitness::Flags: {
if (boundGenericCharacteristics)
return B.addInt32(
getValueWitnessFlags(boundGenericCharacteristics->TI,
getValueWitnessFlags(IGM,
boundGenericCharacteristics->TI,
boundGenericCharacteristics->concreteType,
boundGenericCharacteristics->packing)
.getOpaqueValue());
return B.addInt32(getValueWitnessFlags(&concreteTI, concreteType, packing)
return B.addInt32(getValueWitnessFlags(IGM, &concreteTI,
concreteType, packing)
.getOpaqueValue());
}
@@ -1441,7 +1452,7 @@ getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type,
auto &ti = IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(), type);
// We only have known value witness tables for copyable types currently.
// We only have known value witness tables for copyable types currently.
if (!ti.isCopyable(ResilienceExpansion::Maximal)) {
return {};
}
@@ -1454,6 +1465,17 @@ getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type,
CanType witnessSurrogate;
ReferenceCounting refCounting;
// All of our standard value witness tables are bitwise-borrowable and not
// addressable for dependencies.
if (!ti.isBitwiseBorrowable(ResilienceExpansion::Maximal)
|| IGM.getSILModule().Types
.getTypeLowering(AbstractionPattern::getOpaque(), type,
TypeExpansionContext::minimal())
.getRecursiveProperties()
.isAddressableForDependencies()) {
return {};
}
// Empty types can use empty tuple witnesses.
if (ti.isKnownEmpty(ResilienceExpansion::Maximal)) {
witnessSurrogate = TupleType::getEmpty(C);

View File

@@ -0,0 +1,19 @@
// RUN: %empty-directory(%t)
// RUN: %{python} %utils/chex.py < %s > %t/test.swift
// RUN: %target-swift-frontend -enable-experimental-feature AddressableTypes -emit-ir %s | %FileCheck %t/test.swift
// REQUIRES: swift_feature_AddressableTypes
@_addressableForDependencies
struct DirectlyAFD {
var x: Int32
}
// CHECK-LABEL: @"$s{{.*}}11DirectlyAFDVWV" =
// -- 0x0200_0000: addressable for dependencies
// CHECK-SAME: , [[WORD:i(64|32)]] 4, [[WORD]] 4, <i32 0x0200_0003>, i32 0 }
struct IndirectlyAFD {
var directly: DirectlyAFD
}
// CHECK-LABEL: @"$s{{.*}}13IndirectlyAFDVWV" =
// CHECK-SAME: , [[WORD:i(64|32)]] 4, [[WORD]] 4, <i32 0x0200_0003>, i32 0 }

View File

@@ -13,8 +13,8 @@ import RawLayoutCXX
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
@_rawLayout(size: 4, alignment: 4)
struct Lock: ~Copyable { }
@@ -29,8 +29,8 @@ struct PaddedStride {
// CHECK-SAME: , {{i64|i32}} 5
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
@_rawLayout(like: PaddedStride)
struct LikePaddedStride: ~Copyable {}
@@ -39,8 +39,8 @@ struct LikePaddedStride: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
@_rawLayout(likeArrayOf: PaddedStride, count: 1)
struct LikePaddedStrideArray1: ~Copyable {}
@@ -49,9 +49,9 @@ struct LikePaddedStrideArray1: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 16
// stride
// CHECK-SAME: , {{i64|i32}} 16
// flags: alignment 3, noncopyable, non-bitwise-borrowable, (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x1800003>
// CHECK-32-SAME: , <i32 0x1820003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x3800003>
// CHECK-32-SAME: , <i32 0x3820003>
@_rawLayout(likeArrayOf: PaddedStride, count: 2)
struct LikePaddedStrideArray2: ~Copyable {}
@@ -60,8 +60,8 @@ struct LikePaddedStrideArray2: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 12
// stride
// CHECK-SAME: , {{i64|i32}} 12
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
struct Keymaster: ~Copyable {
let lock1: Lock
let lock2: Lock
@@ -127,8 +127,8 @@ struct Vector<T, let N: Int>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
struct UsesCell: ~Copyable {
let someCondition: Bool
let specialInt: Cell<Int32>
@@ -139,8 +139,8 @@ struct UsesCell: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 3
// stride
// CHECK-SAME: , {{i64|i32}} 3
// flags: alignment 0, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800000>
// flags: alignment 0, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800000>
struct BufferOf3Bool: ~Copyable {
let buffer: SmallVectorOf3<Bool>
}
@@ -150,8 +150,8 @@ struct BufferOf3Bool: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 48
// stride
// CHECK-SAME: , {{i64|i32}} 48
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME: , <i32 0x1820007>
// flags: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies, is not inline
// CHECK-SAME: , <i32 0x3820007>
struct BadBuffer: ~Copyable {
let buffer: SmallVectorOf3<Int64?>
}
@@ -161,8 +161,8 @@ struct BadBuffer: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 2
// stride
// CHECK-SAME: , {{i64|i32}} 2
// flags: alignment 0, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800000>
// flags: alignment 0, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800000>
struct UsesVector: ~Copyable {
let buffer: Vector<UInt8, 2>
}
@@ -172,8 +172,8 @@ struct UsesVector: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 48
// stride
// CHECK-SAME: , {{i64|i32}} 48
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME: , <i32 0x1820007>
// flags: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies, is not inline
// CHECK-SAME: , <i32 0x3820007>
struct BadBuffer2: ~Copyable {
let buffer: Vector<Int64?, 3>
}
@@ -207,8 +207,8 @@ struct CellThatMovesAsLike<T>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 1
// stride
// CHECK-SAME: , {{i64|i32}} 1
// flags: not copyable, not bitwise takable, not pod, not inline
// CHECK-SAME: , <i32 0x930000>
// flags: not copyable, not bitwise takable, not pod, not inline, addressable for dependencies
// CHECK-SAME: , <i32 0x2930000>
struct ConcreteMoveAsLike: ~Copyable {
let cell: CellThatMovesAsLike<NonBitwiseTakableCXXType>
}
@@ -224,8 +224,8 @@ struct ConcreteMoveAsLike: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: alignment 3, not copyable, not bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, not copyable, not bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
struct ConcreteIntMoveAsLike: ~Copyable {
let cell: CellThatMovesAsLike<Int32>
}
@@ -257,8 +257,8 @@ struct SmallVectorOf2MovesAsLike<T: ~Copyable>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 2
// stride
// CHECK-SAME: , {{i64|i32}} 2
// flags: not copyable, not bitwise takable, not pod, not inline
// CHECK-SAME: , <i32 0x930000>
// flags: not copyable, not bitwise takable, not pod, not inline, addressable for dependencies
// CHECK-SAME: , <i32 0x2930000>
struct ConcreteSmallVectorMovesAsLike: ~Copyable {
let vector: SmallVectorOf2MovesAsLike<NonBitwiseTakableCXXType>
}
@@ -274,8 +274,8 @@ struct ConcreteSmallVectorMovesAsLike: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// flags: alignment 3, not copyable, not bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, not copyable, not bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x3800003>
struct ConcreteSmallVectorIntMovesAsLike: ~Copyable {
let vector: SmallVectorOf2MovesAsLike<Int32>
}
@@ -307,8 +307,8 @@ struct VectorMovesAsLike<T: ~Copyable, let N: Int>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: not copyable, not bitwise takable, not pod, not inline
// CHECK-SAME: , <i32 0x930000>
// flags: not copyable, not bitwise takable, not pod, not inline, addressable for dependencies
// CHECK-SAME: , <i32 0x2930000>
struct ConcreteVectorMovesAsLike: ~Copyable {
let vector: VectorMovesAsLike<NonBitwiseTakableCXXType, 4>
}
@@ -324,9 +324,9 @@ struct ConcreteVectorMovesAsLike: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 16
// stride
// CHECK-SAME: , {{i64|i32}} 16
// 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>
// flags: alignment 3, not copyable, not bitwise-borrowable, addressable for dependencies, (on 32-bit platforms) not storable inline
// CHECK-64-SAME: , <i32 0x3800003>
// CHECK-32-SAME: , <i32 0x3820003>
struct ConcreteVectorIntMovesAsLike: ~Copyable {
let vector: VectorMovesAsLike<Int32, 4>
}

View File

@@ -13,8 +13,8 @@ public struct Foo<T>: ~Copyable {}
// CHECK-SAME: , {{i64|i32}} 4
// stride
// CHECK-SAME: , {{i64|i32}} 4
// flags: alignment 3, noncopyable, non-bitwise-borrowable
// CHECK-SAME: , <i32 0x1800003>
// flags: alignment 3, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME: , <i32 0x380_0003>
struct MyInt: ~Copyable {
let x: Int32Fake
}
@@ -24,8 +24,8 @@ struct MyInt: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 48
// stride
// CHECK-SAME: , {{i64|i32}} 48
// flags: alignment 7, noncopyable, non-bitwise-borrowable, is not inline
// CHECK-SAME: , <i32 0x1820007>
// flags: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies, is not inline
// CHECK-SAME: , <i32 0x382_0007>
struct BadBuffer: ~Copyable {
let buf = SmallVectorOf3<Int64?>()
}
@@ -35,10 +35,10 @@ struct BadBuffer: ~Copyable {
// CHECK-SAME: , {{i64|i32}} 8
// stride
// CHECK-SAME: , {{i64|i32}} 8
// 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>
// flags-32: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies, is not inline
// CHECK-SAME-32: , <i32 0x3820007>
// flags-64: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-SAME-64: , <i32 0x3800007>
struct Weird: ~Copyable {
let value = UnsafeCell<Int64>()
}

View File

@@ -18,8 +18,8 @@ import RawLayoutCXX
// CHECK-SAME: , {{i64|i32}} 1
// stride
// CHECK-SAME: , {{i64|i32}} 1
// flags: not copyable, not bitwise takable, not pod, not inline
// CHECK-SAME: , i32 9633792
// flags: addressable for dependencies, not copyable, not bitwise takable, not pod, not inline
// CHECK-SAME: , i32 43188224
struct WeirdCXXTypeCell: ~Copyable {
let cell: CellThatMovesLike<NonBitwiseTakableCXXType>
}