Skip to content

Commit 8b48a0d

Browse files
authored
[Runtime+IRGen] Instantiate layout strings for generic multi payload enum (#66621)
Instantiating layout strings for generic types reduces code size and is expected to improve performance of generic value witnesses.
1 parent d06e8c9 commit 8b48a0d

File tree

11 files changed

+362
-76
lines changed

11 files changed

+362
-76
lines changed

include/swift/Runtime/Enum.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ void swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
111111
unsigned numPayloads,
112112
const TypeLayout * const *payloadTypes);
113113

114+
SWIFT_RUNTIME_EXPORT
115+
void swift_initEnumMetadataMultiPayloadWithLayoutString(EnumMetadata *enumType,
116+
EnumLayoutFlags flags,
117+
unsigned numPayloads,
118+
const Metadata * const *payloadTypes);
119+
114120
/// Return an integer value representing which case of a multi-payload
115121
/// enum is inhabited.
116122
///

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,8 @@ FUNCTION(InitStructMetadata,
12761276
// void swift_initStructMetadataWithLayoutString(Metadata *structType,
12771277
// StructLayoutFlags flags,
12781278
// size_t numFields,
1279-
// Metadata * const *fieldTypes,
1279+
// uint8_t * const *fieldTypes,
1280+
// const uint8_t *fieldTags
12801281
// uint32_t *fieldOffsets);
12811282
FUNCTION(InitStructMetadataWithLayoutString,
12821283
swift_initStructMetadataWithLayoutString, C_CC, AlwaysAvailable,
@@ -1312,6 +1313,7 @@ FUNCTION(InitEnumMetadataSinglePayload,
13121313
EFFECT(MetaData))
13131314

13141315
// void swift_initEnumMetadataMultiPayload(Metadata *enumType,
1316+
// EnumLayoutFlags layoutFlags,
13151317
// size_t numPayloads,
13161318
// TypeLayout * const *payloadTypes);
13171319
FUNCTION(InitEnumMetadataMultiPayload,
@@ -1322,6 +1324,19 @@ FUNCTION(InitEnumMetadataMultiPayload,
13221324
ATTRS(NoUnwind, WillReturn),
13231325
EFFECT(MetaData))
13241326

1327+
// void
1328+
// swift_initEnumMetadataMultiPayloadWithLayoutString(Metadata *enumType,
1329+
// EnumLayoutFlags layoutFlags,
1330+
// size_t numPayloads,
1331+
// Metadata * const *payloadTypes);
1332+
FUNCTION(InitEnumMetadataMultiPayloadWithLayoutString,
1333+
swift_initEnumMetadataMultiPayloadWithLayoutString,
1334+
C_CC, AlwaysAvailable,
1335+
RETURNS(VoidTy),
1336+
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, TypeMetadataPtrPtrTy),
1337+
ATTRS(NoUnwind, WillReturn),
1338+
EFFECT(MetaData))
1339+
13251340
// int swift_getEnumCaseMultiPayload(opaque_t *obj, Metadata *enumTy);
13261341
FUNCTION(GetEnumCaseMultiPayload,
13271342
swift_getEnumCaseMultiPayload,

lib/IRGen/GenEnum.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,15 @@ namespace {
663663
metadata);
664664
}
665665

666+
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
667+
llvm::Value *metadata,
668+
bool isVWTMutable,
669+
SILType T,
670+
MetadataDependencyCollector *collector) const override {
671+
// Not yet supported on this type, so forward to regular method
672+
initializeMetadata(IGF, metadata, isVWTMutable, T, collector);
673+
}
674+
666675
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
667676
// FIXME: Hold off on registering extra inhabitants for dynamic enums
668677
// until initializeMetadata handles them.
@@ -964,6 +973,15 @@ namespace {
964973
// witness table initialization.
965974
}
966975

976+
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
977+
llvm::Value *metadata,
978+
bool isVWTMutable,
979+
SILType T,
980+
MetadataDependencyCollector *collector) const override {
981+
// No-payload enums are always fixed-size so never need dynamic value
982+
// witness table initialization.
983+
}
984+
967985
/// \group Required for SingleScalarTypeInfo
968986

969987
llvm::Type *getScalarType() const {
@@ -3189,6 +3207,15 @@ namespace {
31893207
{metadata, flags, payloadLayout, emptyCasesVal});
31903208
}
31913209

3210+
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
3211+
llvm::Value *metadata,
3212+
bool isVWTMutable,
3213+
SILType T,
3214+
MetadataDependencyCollector *collector) const override {
3215+
// Not yet supported on this type, so forward to regular method
3216+
initializeMetadata(IGF, metadata, isVWTMutable, T, collector);
3217+
}
3218+
31923219
/// \group Extra inhabitants
31933220

31943221
// Extra inhabitants from the payload that we didn't use for our empty cases
@@ -5259,6 +5286,36 @@ namespace {
52595286
return firstAddr;
52605287
}
52615288

5289+
llvm::Value *emitPayloadMetadataArray(IRGenFunction &IGF, SILType T,
5290+
MetadataDependencyCollector *collector) const {
5291+
auto numPayloads = ElementsWithPayload.size();
5292+
auto metadataBufferTy = llvm::ArrayType::get(IGM.TypeMetadataPtrTy,
5293+
numPayloads);
5294+
auto metadataBuffer = IGF.createAlloca(metadataBufferTy,
5295+
IGM.getPointerAlignment(),
5296+
"payload_types");
5297+
llvm::Value *firstAddr = nullptr;
5298+
for (unsigned i = 0; i < numPayloads; ++i) {
5299+
auto &elt = ElementsWithPayload[i];
5300+
Address eltAddr = IGF.Builder.CreateStructGEP(metadataBuffer, i,
5301+
IGM.getPointerSize() * i);
5302+
if (i == 0) firstAddr = eltAddr.getAddress();
5303+
5304+
auto payloadTy =
5305+
T.getEnumElementType(elt.decl, IGF.getSILModule(),
5306+
IGF.IGM.getMaximalTypeExpansionContext());
5307+
5308+
auto request = DynamicMetadataRequest::getNonBlocking(
5309+
MetadataState::LayoutComplete, collector);
5310+
auto metadata = IGF.emitTypeMetadataRefForLayout(payloadTy, request);
5311+
5312+
IGF.Builder.CreateStore(metadata, eltAddr);
5313+
}
5314+
assert(firstAddr && "Expected firstAddr to be assigned to");
5315+
5316+
return firstAddr;
5317+
}
5318+
52625319
void initializeMetadata(IRGenFunction &IGF,
52635320
llvm::Value *metadata,
52645321
bool isVWTMutable,
@@ -5278,6 +5335,25 @@ namespace {
52785335
{metadata, flags, numPayloadsVal, payloadLayoutArray});
52795336
}
52805337

5338+
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
5339+
llvm::Value *metadata,
5340+
bool isVWTMutable,
5341+
SILType T,
5342+
MetadataDependencyCollector *collector) const override {
5343+
// Fixed-size enums don't need dynamic metadata initialization.
5344+
if (TIK >= Fixed) return;
5345+
5346+
// Ask the runtime to set up the metadata record for a dynamic enum.
5347+
auto payloadLayoutArray = emitPayloadMetadataArray(IGF, T, collector);
5348+
auto numPayloadsVal = llvm::ConstantInt::get(IGM.SizeTy,
5349+
ElementsWithPayload.size());
5350+
5351+
auto flags = emitEnumLayoutFlags(IGM, isVWTMutable);
5352+
IGF.Builder.CreateCall(
5353+
IGM.getInitEnumMetadataMultiPayloadWithLayoutStringFunctionPointer(),
5354+
{metadata, flags, numPayloadsVal, payloadLayoutArray});
5355+
}
5356+
52815357
/// \group Extra inhabitants
52825358

52835359
// If we didn't use all of the available tag bit representations, offer
@@ -5959,6 +6035,14 @@ namespace {
59596035
llvm_unreachable("resilient enums cannot be defined");
59606036
}
59616037

6038+
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
6039+
llvm::Value *metadata,
6040+
bool isVWTMutable,
6041+
SILType T,
6042+
MetadataDependencyCollector *collector) const override {
6043+
llvm_unreachable("resilient enums cannot be defined");
6044+
}
6045+
59626046
/// \group Extra inhabitants
59636047

59646048
bool mayHaveExtraInhabitants(IRGenModule &) const override {

lib/IRGen/GenEnum.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,12 @@ class EnumImplStrategy {
384384
SILType T,
385385
MetadataDependencyCollector *collector) const = 0;
386386

387+
virtual void initializeMetadataWithLayoutString(IRGenFunction &IGF,
388+
llvm::Value *metadata,
389+
bool isVWTMutable,
390+
SILType T,
391+
MetadataDependencyCollector *collector) const = 0;
392+
387393
virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0;
388394

389395
// Only ever called for fixed types.

lib/IRGen/GenMeta.cpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3003,16 +3003,17 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF,
30033003
MetadataDependencyCollector *collector) {
30043004
auto &IGM = IGF.IGM;
30053005
auto loweredTy = IGM.getLoweredType(nominalDecl->getDeclaredTypeInContext());
3006+
bool useLayoutStrings = IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) &&
3007+
IGM.Context.LangOpts.hasFeature(
3008+
Feature::LayoutStringValueWitnessesInstantiation) &&
3009+
IGM.getOptions().EnableLayoutStringValueWitnesses &&
3010+
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation;
30063011

30073012
if (isa<StructDecl>(nominalDecl)) {
30083013
auto &fixedTI = IGM.getTypeInfo(loweredTy);
30093014
if (isa<FixedTypeInfo>(fixedTI)) return;
30103015

3011-
if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) &&
3012-
IGM.Context.LangOpts.hasFeature(
3013-
Feature::LayoutStringValueWitnessesInstantiation) &&
3014-
IGM.getOptions().EnableLayoutStringValueWitnesses &&
3015-
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation) {
3016+
if (useLayoutStrings) {
30163017
emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata,
30173018
isVWTMutable, collector);
30183019
} else {
@@ -3021,9 +3022,16 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF,
30213022
}
30223023
} else {
30233024
assert(isa<EnumDecl>(nominalDecl));
3025+
30243026
auto &strategy = getEnumImplStrategy(IGM, loweredTy);
3025-
strategy.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy,
3026-
collector);
3027+
3028+
if (useLayoutStrings) {
3029+
strategy.initializeMetadataWithLayoutString(IGF, metadata, isVWTMutable,
3030+
loweredTy, collector);
3031+
} else {
3032+
strategy.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy,
3033+
collector);
3034+
}
30273035
}
30283036
}
30293037

@@ -5721,10 +5729,28 @@ namespace {
57215729
return {global, offset, structSize};
57225730
}
57235731

5732+
bool hasLayoutString() {
5733+
if (!IGM.Context.LangOpts.hasFeature(
5734+
Feature::LayoutStringValueWitnesses) ||
5735+
!IGM.getOptions().EnableLayoutStringValueWitnesses) {
5736+
return false;
5737+
}
5738+
5739+
auto &strategy = getEnumImplStrategy(IGM, getLoweredType());
5740+
5741+
return !!getLayoutString() ||
5742+
(IGM.Context.LangOpts.hasFeature(
5743+
Feature::LayoutStringValueWitnessesInstantiation) &&
5744+
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
5745+
(HasDependentVWT || HasDependentMetadata) &&
5746+
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) &&
5747+
strategy.getElementsWithPayload().size() > 1);
5748+
}
5749+
57245750
llvm::Constant *emitNominalTypeDescriptor() {
57255751
return EnumContextDescriptorBuilder(
57265752
IGM, Target, RequireMetadata,
5727-
/*hasLayoutString*/ !!getLayoutString())
5753+
/*hasLayoutString*/ hasLayoutString())
57285754
.emit();
57295755
}
57305756

@@ -5746,7 +5772,7 @@ namespace {
57465772

57475773
bool hasCompletionFunction() {
57485774
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) ||
5749-
!!getLayoutString();
5775+
hasLayoutString();
57505776
}
57515777
};
57525778

lib/IRGen/GenValueWitness.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,9 @@ bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM,
891891
IGM.Context.LangOpts.hasFeature(
892892
Feature::LayoutStringValueWitnessesInstantiation) &&
893893
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation) {
894+
if (auto *enumEntry = typeLayoutEntry->getAsEnum()) {
895+
return enumEntry->isMultiPayloadEnum();
896+
}
894897
return (typeLayoutEntry->isAlignedGroup() &&
895898
!typeLayoutEntry->isFixedSize(IGM));
896899
}

lib/IRGen/TypeLayout.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class LayoutStringBuilder {
8383
MultiPayloadEnumFN = 0x13,
8484
// reserved
8585
// MultiPayloadEnumFNResolved = 0x14,
86+
// MultiPayloadEnumGeneric = 0x15,
8687

8788
Skip = 0x80,
8889
// We may use the MSB as flag that a count follows,

0 commit comments

Comments
 (0)