Skip to content

Commit 1e8445f

Browse files
authored
Merge pull request #13570 from rjmccall/metadata-init-abi
2 parents 22dcabf + 9bbbe2c commit 1e8445f

26 files changed

+320
-306
lines changed

docs/Runtime.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,9 @@ runtime.
314314
000000000001e620 T _swift_allocateGenericValueMetadata
315315
0000000000022be0 T _swift_initClassMetadata_UniversalStrategy
316316
000000000001c100 T _swift_initEnumMetadataMultiPayload
317-
000000000001bd60 T _swift_initEnumValueWitnessTableSinglePayload
318-
0000000000022a20 T _swift_initStructMetadata_UniversalStrategy
317+
000000000001bd60 T _swift_initEnumMetadataSingleCase
318+
000000000001bd60 T _swift_initEnumMetadataSinglePayload
319+
0000000000022a20 T _swift_initStructMetadata
319320
0000000000024230 T _swift_initializeSuperclass
320321
0000000000028b60 T _swift_instantiateObjCClass
321322
```

include/swift/ABI/MetadataValues.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,62 @@ static inline bool isWarningOnly(ExclusivityFlags flags) {
747747
return uintptr_t(flags) & uintptr_t(ExclusivityFlags::WarningOnly);
748748
}
749749

750+
/// Flags for struct layout.
751+
enum class StructLayoutFlags : uintptr_t {
752+
/// Reserve space for 256 layout algorithms.
753+
AlgorithmMask = 0xff,
754+
755+
/// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
756+
Swift5Algorithm = 0x00,
757+
758+
/// Is the value-witness table mutable in place, or does layout need to
759+
/// clone it?
760+
IsVWTMutable = 0x100,
761+
};
762+
static inline StructLayoutFlags operator|(StructLayoutFlags lhs,
763+
StructLayoutFlags rhs) {
764+
return StructLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
765+
}
766+
static inline StructLayoutFlags &operator|=(StructLayoutFlags &lhs,
767+
StructLayoutFlags rhs) {
768+
return (lhs = (lhs | rhs));
769+
}
770+
static inline StructLayoutFlags getLayoutAlgorithm(StructLayoutFlags flags) {
771+
return StructLayoutFlags(uintptr_t(flags)
772+
& uintptr_t(StructLayoutFlags::AlgorithmMask));
773+
}
774+
static inline bool isValueWitnessTableMutable(StructLayoutFlags flags) {
775+
return uintptr_t(flags) & uintptr_t(StructLayoutFlags::IsVWTMutable);
776+
}
777+
778+
/// Flags for enum layout.
779+
enum class EnumLayoutFlags : uintptr_t {
780+
/// Reserve space for 256 layout algorithms.
781+
AlgorithmMask = 0xff,
782+
783+
/// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
784+
Swift5Algorithm = 0x00,
785+
786+
/// Is the value-witness table mutable in place, or does layout need to
787+
/// clone it?
788+
IsVWTMutable = 0x100,
789+
};
790+
static inline EnumLayoutFlags operator|(EnumLayoutFlags lhs,
791+
EnumLayoutFlags rhs) {
792+
return EnumLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
793+
}
794+
static inline EnumLayoutFlags &operator|=(EnumLayoutFlags &lhs,
795+
EnumLayoutFlags rhs) {
796+
return (lhs = (lhs | rhs));
797+
}
798+
static inline EnumLayoutFlags getLayoutAlgorithm(EnumLayoutFlags flags) {
799+
return EnumLayoutFlags(uintptr_t(flags)
800+
& uintptr_t(EnumLayoutFlags::AlgorithmMask));
801+
}
802+
static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) {
803+
return uintptr_t(flags) & uintptr_t(EnumLayoutFlags::IsVWTMutable);
804+
}
805+
750806
} // end namespace swift
751807

752808
#endif /* SWIFT_ABI_METADATAVALUES_H */

include/swift/Runtime/Enum.h

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,29 @@ template <typename Runtime> struct TargetEnumMetadata;
3333
using EnumMetadata = TargetEnumMetadata<InProcess>;
3434
struct TypeLayout;
3535

36-
/// \brief Initialize the value witness table for a generic, single-payload
37-
/// enum instance.
36+
/// \brief Initialize the type metadata for a single-case enum type.
37+
///
38+
/// \param enumType - pointer to the instantiated but uninitialized metadata
39+
/// for the enum.
40+
/// \param flags - flags controlling the layout
41+
/// \param payload - type metadata for the payload of the enum.
42+
SWIFT_RUNTIME_EXPORT
43+
void swift_initEnumMetadataSingleCase(EnumMetadata *enumType,
44+
EnumLayoutFlags flags,
45+
const TypeLayout *payload);
46+
47+
/// \brief Initialize the type metadata for a single-payload enum type.
3848
///
39-
/// \param vwtable - pointer to the instantiated but uninitialized value
40-
/// witness table for the enum.
49+
/// \param enumType - pointer to the instantiated but uninitialized metadata
50+
/// for the enum.
51+
/// \param flags - flags controlling the layout
4152
/// \param payload - type metadata for the payload case of the enum.
4253
/// \param emptyCases - the number of empty cases in the enum.
4354
SWIFT_RUNTIME_EXPORT
44-
void swift_initEnumValueWitnessTableSinglePayload(ValueWitnessTable *vwtable,
45-
const TypeLayout *payload,
46-
unsigned emptyCases);
55+
void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType,
56+
EnumLayoutFlags flags,
57+
const TypeLayout *payload,
58+
unsigned emptyCases);
4759

4860
/// \brief Faster variant of the above which avoids digging into the enum type
4961
/// metadata when the caller already has the payload information handy.
@@ -81,11 +93,11 @@ void swift_storeEnumTagSinglePayload(OpaqueValue *value,
8193
unsigned emptyCases)
8294
SWIFT_CC(RegisterPreservingCC);
8395

84-
/// \brief Initialize the value witness table for a generic, multi-payload
96+
/// \brief Initialize the type metadata for a generic, multi-payload
8597
/// enum instance.
8698
SWIFT_RUNTIME_EXPORT
87-
void swift_initEnumMetadataMultiPayload(ValueWitnessTable *vwtable,
88-
EnumMetadata *enumType,
99+
void swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
100+
EnumLayoutFlags flags,
89101
unsigned numPayloads,
90102
const TypeLayout * const *payloadTypes);
91103

include/swift/Runtime/Metadata.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2967,10 +2967,11 @@ swift_getTupleTypeMetadata3(const Metadata *elt0, const Metadata *elt1,
29672967
/// Initialize the value witness table and struct field offset vector for a
29682968
/// struct, using the "Universal" layout strategy.
29692969
SWIFT_RUNTIME_EXPORT
2970-
void swift_initStructMetadata_UniversalStrategy(size_t numFields,
2971-
const TypeLayout * const *fieldTypes,
2972-
size_t *fieldOffsets,
2973-
ValueWitnessTable *vwtable);
2970+
void swift_initStructMetadata(StructMetadata *self,
2971+
StructLayoutFlags flags,
2972+
size_t numFields,
2973+
const TypeLayout * const *fieldTypes,
2974+
size_t *fieldOffsets);
29742975

29752976
/// Relocate the metadata for a class and copy fields from the given template.
29762977
/// The final size of the metadata is calculated at runtime from the size of

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -968,37 +968,47 @@ FUNCTION(InitClassMetadataUniversal,
968968
SizeTy->getPointerTo()),
969969
ATTRS(NoUnwind))
970970

971-
// void swift_initStructMetadata_UniversalStrategy(size_t numFields,
972-
// TypeLayout * const *fieldTypes,
973-
// size_t *fieldOffsets,
974-
// value_witness_table_t *vwtable);
975-
FUNCTION(InitStructMetadataUniversal,
976-
swift_initStructMetadata_UniversalStrategy, DefaultCC,
977-
RETURNS(VoidTy),
978-
ARGS(SizeTy, Int8PtrPtrTy->getPointerTo(),
979-
SizeTy->getPointerTo(), WitnessTablePtrTy),
980-
ATTRS(NoUnwind))
981-
982-
// void swift_initEnumValueWitnessTableSinglePayload(value_witness_table_t *vwt,
983-
// TypeLayout *payload,
984-
// unsigned num_empty_cases);
985-
FUNCTION(InitEnumValueWitnessTableSinglePayload,
986-
swift_initEnumValueWitnessTableSinglePayload,
971+
// void swift_initStructMetadata(Metadata *structType,
972+
// StructLayoutFlags flags,
973+
// size_t numFields,
974+
// TypeLayout * const *fieldTypes,
975+
// size_t *fieldOffsets);
976+
FUNCTION(InitStructMetadata,
977+
swift_initStructMetadata, DefaultCC,
978+
RETURNS(VoidTy),
979+
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0),
980+
SizeTy->getPointerTo()),
981+
ATTRS(NoUnwind))
982+
983+
// void swift_initEnumMetadataSingleCase(Metadata *enumType,
984+
// EnumLayoutFlags flags,
985+
// TypeLayout *payload);
986+
FUNCTION(InitEnumMetadataSingleCase,
987+
swift_initEnumMetadataSingleCase,
988+
DefaultCC,
989+
RETURNS(VoidTy),
990+
ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy),
991+
ATTRS(NoUnwind))
992+
993+
// void swift_initEnumMetadataSinglePayload(Metadata *enumType,
994+
// EnumLayoutFlags flags,
995+
// TypeLayout *payload,
996+
// unsigned num_empty_cases);
997+
FUNCTION(InitEnumMetadataSinglePayload,
998+
swift_initEnumMetadataSinglePayload,
987999
DefaultCC,
9881000
RETURNS(VoidTy),
989-
ARGS(WitnessTablePtrTy, Int8PtrPtrTy, Int32Ty),
1001+
ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy, Int32Ty),
9901002
ATTRS(NoUnwind))
9911003

992-
// void swift_initEnumMetadataMultiPayload(value_witness_table_t *vwt,
993-
// Metadata *enumType,
1004+
// void swift_initEnumMetadataMultiPayload(Metadata *enumType,
9941005
// size_t numPayloads,
9951006
// TypeLayout * const *payloadTypes);
9961007
FUNCTION(InitEnumMetadataMultiPayload,
9971008
swift_initEnumMetadataMultiPayload,
9981009
DefaultCC,
9991010
RETURNS(VoidTy),
1000-
ARGS(WitnessTablePtrTy, TypeMetadataPtrTy, SizeTy,
1001-
Int8PtrPtrTy->getPointerTo(0)),
1011+
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0)),
10021012
ATTRS(NoUnwind))
10031013

10041014
// int swift_getEnumCaseSinglePayload(opaque_t *obj, Metadata *payload,

lib/IRGen/FixedTypeInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class FixedTypeInfo : public TypeInfo {
226226
/// Fixed-size types never need dynamic value witness table instantiation.
227227
void initializeMetadata(IRGenFunction &IGF,
228228
llvm::Value *metadata,
229-
llvm::Value *vwtable,
229+
bool isVWTMutable,
230230
SILType T) const override {}
231231

232232
void collectArchetypeMetadata(

lib/IRGen/GenEnum.cpp

Lines changed: 28 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@
130130
using namespace swift;
131131
using namespace irgen;
132132

133+
static llvm::Constant *emitEnumLayoutFlags(IRGenModule &IGM, bool isVWTMutable){
134+
// For now, we always use the Swift 5 algorithm.
135+
auto flags = EnumLayoutFlags::Swift5Algorithm;
136+
if (isVWTMutable) flags |= EnumLayoutFlags::IsVWTMutable;
137+
138+
return IGM.getSize(Size(uintptr_t(flags)));
139+
}
140+
133141
SpareBitVector getBitVectorFromAPInt(const APInt &bits, unsigned startBit = 0) {
134142
if (startBit == 0) {
135143
return SpareBitVector::fromAPInt(bits);
@@ -587,78 +595,21 @@ namespace {
587595

588596
void initializeMetadata(IRGenFunction &IGF,
589597
llvm::Value *metadata,
590-
llvm::Value *vwtable,
598+
bool isVWTMutable,
591599
SILType T) const override {
592600
// Fixed-size enums don't need dynamic witness table initialization.
593601
if (TIK >= Fixed) return;
594602

595-
assert(!ElementsWithPayload.empty() &&
603+
assert(ElementsWithPayload.size() == 1 &&
596604
"empty singleton enum should not be dynamic!");
597605

598-
// Get the value witness table for the element.
599-
SILType eltTy = T.getEnumElementType(ElementsWithPayload[0].decl,
600-
IGM.getSILModule());
601-
llvm::Value *eltLayout = IGF.emitTypeLayoutRef(eltTy);
602-
603-
Address vwtAddr(vwtable, IGF.IGM.getPointerAlignment());
604-
Address eltLayoutAddr(eltLayout, IGF.IGM.getPointerAlignment());
605-
606-
auto getWitnessDestAndSrc = [&](ValueWitness witness,
607-
Address *dest,
608-
Address *src) {
609-
*dest = IGF.Builder.CreateConstArrayGEP(vwtAddr,
610-
unsigned(witness), IGF.IGM.getPointerSize());
611-
*src = IGF.Builder.CreateConstArrayGEP(eltLayoutAddr,
612-
unsigned(witness) - unsigned(ValueWitness::First_TypeLayoutWitness),
613-
IGF.IGM.getPointerSize());
614-
};
615-
616-
auto copyWitnessFromElt = [&](ValueWitness witness) {
617-
Address dest, src;
618-
getWitnessDestAndSrc(witness, &dest, &src);
619-
auto val = IGF.Builder.CreateLoad(src);
620-
IGF.Builder.CreateStore(val, dest);
621-
};
622-
623-
copyWitnessFromElt(ValueWitness::Size);
624-
copyWitnessFromElt(ValueWitness::Stride);
625-
626-
// Copy flags over, adding HasEnumWitnesses flag
627-
auto copyFlagsFromElt = [&](ValueWitness witness) -> llvm::Value* {
628-
Address dest, src;
629-
getWitnessDestAndSrc(witness, &dest, &src);
630-
auto val = IGF.Builder.CreateLoad(src);
631-
auto ewFlag = IGF.Builder.CreatePtrToInt(val, IGF.IGM.SizeTy);
632-
auto ewMask
633-
= IGF.IGM.getSize(Size(ValueWitnessFlags::HasEnumWitnesses));
634-
ewFlag = IGF.Builder.CreateOr(ewFlag, ewMask);
635-
auto flag = IGF.Builder.CreateIntToPtr(ewFlag,
636-
dest.getType()->getElementType());
637-
IGF.Builder.CreateStore(flag, dest);
638-
return val;
639-
};
640-
641-
auto flags = copyFlagsFromElt(ValueWitness::Flags);
642-
643-
// If the original type had extra inhabitants, carry over its
644-
// extra inhabitant flags.
645-
auto xiBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
646-
auto noXIBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
647-
648-
auto xiFlag = IGF.Builder.CreatePtrToInt(flags, IGF.IGM.SizeTy);
649-
auto xiMask
650-
= IGF.IGM.getSize(Size(ValueWitnessFlags::Enum_HasExtraInhabitants));
651-
xiFlag = IGF.Builder.CreateAnd(xiFlag, xiMask);
652-
auto xiBool = IGF.Builder.CreateICmpNE(xiFlag,
653-
IGF.IGM.getSize(Size(0)));
654-
IGF.Builder.CreateCondBr(xiBool, xiBB, noXIBB);
655-
656-
IGF.Builder.emitBlock(xiBB);
657-
ConditionalDominanceScope condition(IGF);
658-
copyWitnessFromElt(ValueWitness::ExtraInhabitantFlags);
659-
IGF.Builder.CreateBr(noXIBB);
660-
661-
IGF.Builder.emitBlock(noXIBB);
606+
auto payloadTy = T.getEnumElementType(ElementsWithPayload[0].decl,
607+
IGM.getSILModule());
608+
auto payloadLayout = IGF.emitTypeLayoutRef(payloadTy);
609+
auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
610+
IGF.Builder.CreateCall(
611+
IGF.IGM.getInitEnumMetadataSingleCaseFn(),
612+
{metadata, flags, payloadLayout});
662613
}
663614

664615
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
@@ -904,7 +855,7 @@ namespace {
904855

905856
void initializeMetadata(IRGenFunction &IGF,
906857
llvm::Value *metadata,
907-
llvm::Value *vwtable,
858+
bool isVWTMutable,
908859
SILType T) const override {
909860
// No-payload enums are always fixed-size so never need dynamic value
910861
// witness table initialization.
@@ -2846,7 +2797,7 @@ namespace {
28462797

28472798
void initializeMetadata(IRGenFunction &IGF,
28482799
llvm::Value *metadata,
2849-
llvm::Value *vwtable,
2800+
bool isVWTMutable,
28502801
SILType T) const override {
28512802
// Fixed-size enums don't need dynamic witness table initialization.
28522803
if (TIK >= Fixed) return;
@@ -2858,10 +2809,10 @@ namespace {
28582809
auto payloadLayout = IGF.emitTypeLayoutRef(payloadTy);
28592810
auto emptyCasesVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
28602811
ElementsWithNoPayload.size());
2861-
2812+
auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
28622813
IGF.Builder.CreateCall(
2863-
IGF.IGM.getInitEnumValueWitnessTableSinglePayloadFn(),
2864-
{vwtable, payloadLayout, emptyCasesVal});
2814+
IGF.IGM.getInitEnumMetadataSinglePayloadFn(),
2815+
{metadata, flags, payloadLayout, emptyCasesVal});
28652816
}
28662817

28672818
/// \group Extra inhabitants
@@ -4744,7 +4695,7 @@ namespace {
47444695

47454696
void initializeMetadata(IRGenFunction &IGF,
47464697
llvm::Value *metadata,
4747-
llvm::Value *vwtable,
4698+
bool isVWTMutable,
47484699
SILType T) const override {
47494700
// Fixed-size enums don't need dynamic metadata initialization.
47504701
if (TIK >= Fixed) return;
@@ -4754,8 +4705,9 @@ namespace {
47544705
auto numPayloadsVal = llvm::ConstantInt::get(IGF.IGM.SizeTy,
47554706
ElementsWithPayload.size());
47564707

4708+
auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
47574709
IGF.Builder.CreateCall(IGF.IGM.getInitEnumMetadataMultiPayloadFn(),
4758-
{vwtable, metadata, numPayloadsVal,
4710+
{metadata, flags, numPayloadsVal,
47594711
payloadLayoutArray});
47604712
}
47614713

@@ -5139,7 +5091,7 @@ namespace {
51395091

51405092
void initializeMetadata(IRGenFunction &IGF,
51415093
llvm::Value *metadata,
5142-
llvm::Value *vwtable,
5094+
bool isVWTMutable,
51435095
SILType T) const override {
51445096
llvm_unreachable("resilient enums cannot be defined");
51455097
}
@@ -5392,9 +5344,9 @@ namespace {
53925344
}
53935345
void initializeMetadata(IRGenFunction &IGF,
53945346
llvm::Value *metadata,
5395-
llvm::Value *vwtable,
5347+
bool isVWTMutable,
53965348
SILType T) const override {
5397-
return Strategy.initializeMetadata(IGF, metadata, vwtable, T);
5349+
return Strategy.initializeMetadata(IGF, metadata, isVWTMutable, T);
53985350
}
53995351
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
54005352
return Strategy.mayHaveExtraInhabitants(IGM);

0 commit comments

Comments
 (0)