Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,19 @@ class TargetValueWitnessFlags {
// 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;
Expand Down Expand Up @@ -268,6 +269,19 @@ class TargetValueWitnessFlags {
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
Expand Down
32 changes: 27 additions & 5 deletions lib/IRGen/GenValueWitness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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))
Expand All @@ -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);
}
Expand Down Expand Up @@ -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());
}

Expand Down Expand Up @@ -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 {};
}
Expand All @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions test/IRGen/addressable_for_dependencies_metadata.swift
Original file line number Diff line number Diff line change
@@ -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 }
68 changes: 34 additions & 34 deletions test/IRGen/raw_layout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 { }
Expand All @@ -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 {}

Expand All @@ -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 {}

Expand All @@ -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 {}

Expand All @@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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>
}
Expand All @@ -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?>
}
Expand All @@ -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>
}
Expand All @@ -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>
}
Expand Down Expand Up @@ -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>
}
Expand All @@ -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>
}
Expand Down Expand Up @@ -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>
}
Expand All @@ -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>
}
Expand Down Expand Up @@ -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>
}
Expand All @@ -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>
}
Expand Down
16 changes: 8 additions & 8 deletions test/IRGen/raw_layout_multifile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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?>()
}
Expand All @@ -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-32-SAME: , <i32 0x1820007>
// flags-64: alignment 7, noncopyable, non-bitwise-borrowable
// CHECK-64-SAME: , <i32 0x1800007>
// flags-32: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies, is not inline
// CHECK-32-SAME: , <i32 0x3820007>
// flags-64: alignment 7, noncopyable, non-bitwise-borrowable, addressable for dependencies
// CHECK-64-SAME: , <i32 0x3800007>
struct Weird: ~Copyable {
let value = UnsafeCell<Int64>()
}
Expand Down
4 changes: 2 additions & 2 deletions test/Serialization/raw_layout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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>
}
Expand Down