Skip to content

Commit 493a25f

Browse files
authored
[IRGen+Runtime] Add layout string support for generic single payload enums (#66791)
1 parent 0795ded commit 493a25f

12 files changed

+327
-28
lines changed

include/swift/Runtime/Enum.h

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType,
6363
const TypeLayout *payload,
6464
unsigned emptyCases);
6565

66+
SWIFT_RUNTIME_EXPORT
67+
void swift_initEnumMetadataSinglePayloadWithLayoutString(
68+
EnumMetadata *enumType, EnumLayoutFlags flags, const Metadata *payload,
69+
unsigned emptyCases);
70+
6671
using getExtraInhabitantTag_t =
6772
SWIFT_CC(swift) unsigned (const OpaqueValue *value,
6873
unsigned numExtraInhabitants,

include/swift/Runtime/RuntimeFunctions.def

+12
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,18 @@ FUNCTION(InitEnumMetadataSinglePayload,
13231323
ATTRS(NoUnwind, WillReturn),
13241324
EFFECT(MetaData))
13251325

1326+
// void swift_initEnumMetadataSinglePayloadWithLayoutString(Metadata *enumType,
1327+
// EnumLayoutFlags flags,
1328+
// Metadata *payload,
1329+
// unsigned num_empty_cases);
1330+
FUNCTION(InitEnumMetadataSinglePayloadWithLayoutString,
1331+
swift_initEnumMetadataSinglePayloadWithLayoutString,
1332+
C_CC, AlwaysAvailable,
1333+
RETURNS(VoidTy),
1334+
ARGS(TypeMetadataPtrTy, SizeTy, TypeMetadataPtrTy, Int32Ty),
1335+
ATTRS(NoUnwind, WillReturn),
1336+
EFFECT(MetaData))
1337+
13261338
// void swift_initEnumMetadataMultiPayload(Metadata *enumType,
13271339
// EnumLayoutFlags layoutFlags,
13281340
// size_t numPayloads,

lib/IRGen/GenEnum.cpp

+19-2
Original file line numberDiff line numberDiff line change
@@ -3237,8 +3237,25 @@ namespace {
32373237
void initializeMetadataWithLayoutString(
32383238
IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T,
32393239
MetadataDependencyCollector *collector) const override {
3240-
// Not yet supported on this type, so forward to regular method
3241-
initializeMetadata(IGF, metadata, isVWTMutable, T, collector);
3240+
// Fixed-size enums don't need dynamic witness table initialization.
3241+
if (TIK >= Fixed)
3242+
return;
3243+
3244+
// Ask the runtime to do our layout using the payload metadata and number
3245+
// of empty cases.
3246+
auto payloadTy =
3247+
T.getEnumElementType(ElementsWithPayload[0].decl, IGM.getSILModule(),
3248+
IGM.getMaximalTypeExpansionContext());
3249+
3250+
auto request = DynamicMetadataRequest::getNonBlocking(
3251+
MetadataState::LayoutComplete, collector);
3252+
auto payloadLayout = IGF.emitTypeMetadataRefForLayout(payloadTy, request);
3253+
auto emptyCasesVal =
3254+
llvm::ConstantInt::get(IGM.Int32Ty, ElementsWithNoPayload.size());
3255+
auto flags = emitEnumLayoutFlags(IGM, isVWTMutable);
3256+
IGF.Builder.CreateCall(
3257+
IGM.getInitEnumMetadataSinglePayloadWithLayoutStringFunctionPointer(),
3258+
{metadata, flags, payloadLayout, emptyCasesVal});
32423259
}
32433260

32443261
/// \group Extra inhabitants

lib/IRGen/GenMeta.cpp

+1-7
Original file line numberDiff line numberDiff line change
@@ -5736,18 +5736,12 @@ namespace {
57365736
return false;
57375737
}
57385738

5739-
auto &strategy = getEnumImplStrategy(IGM, getLoweredType());
5740-
bool isSupportedCase = strategy.getElementsWithPayload().size() > 1 ||
5741-
(strategy.getElementsWithPayload().size() == 1 &&
5742-
strategy.getElementsWithNoPayload().empty());
5743-
57445739
return !!getLayoutString() ||
57455740
(IGM.Context.LangOpts.hasFeature(
57465741
Feature::LayoutStringValueWitnessesInstantiation) &&
57475742
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
57485743
(HasDependentVWT || HasDependentMetadata) &&
5749-
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) &&
5750-
isSupportedCase);
5744+
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())));
57515745
}
57525746

57535747
llvm::Constant *emitNominalTypeDescriptor() {

lib/IRGen/GenValueWitness.cpp

+3-5
Original file line numberDiff line numberDiff line change
@@ -891,11 +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() || enumEntry->isSingleton();
896-
}
897-
return (typeLayoutEntry->isAlignedGroup() &&
898-
!typeLayoutEntry->isFixedSize(IGM));
894+
return (
895+
(typeLayoutEntry->isAlignedGroup() || typeLayoutEntry->getAsEnum()) &&
896+
!typeLayoutEntry->isFixedSize(IGM));
899897
}
900898

901899
return false;

lib/IRGen/TypeLayout.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,12 @@ class LayoutStringBuilder {
8080
SinglePayloadEnumFN = 0x11,
8181
// reserved
8282
// SinglePayloadEnumFNResolved = 0x12,
83+
// SinglePayloadEnumGeneric = 0x13,
8384

84-
MultiPayloadEnumFN = 0x13,
85+
MultiPayloadEnumFN = 0x14,
8586
// reserved
86-
// MultiPayloadEnumFNResolved = 0x14,
87-
// MultiPayloadEnumGeneric = 0x15,
87+
// MultiPayloadEnumFNResolved = 0x15,
88+
// MultiPayloadEnumGeneric = 0x16,
8889

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

stdlib/public/runtime/BytecodeLayouts.cpp

+72-2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ inline static bool handleNextRefCount(const Metadata *metadata,
117117
RefCountingKind::SinglePayloadEnumFNResolved)) {
118118
Handler::handleSinglePayloadEnumFN(typeLayout, offset, true, addrOffset,
119119
std::forward<Params>(params)...);
120+
} else if (SWIFT_UNLIKELY(tag == RefCountingKind::SinglePayloadEnumGeneric)) {
121+
Handler::handleSinglePayloadEnumGeneric(typeLayout, offset, addrOffset,
122+
std::forward<Params>(params)...);
120123
} else if (SWIFT_UNLIKELY(tag == RefCountingKind::MultiPayloadEnumFN)) {
121124
Handler::handleMultiPayloadEnumFN(metadata, typeLayout, offset, false,
122125
addrOffset,
@@ -126,8 +129,7 @@ inline static bool handleNextRefCount(const Metadata *metadata,
126129
Handler::handleMultiPayloadEnumFN(metadata, typeLayout, offset, true,
127130
addrOffset,
128131
std::forward<Params>(params)...);
129-
} else if (SWIFT_UNLIKELY(tag ==
130-
RefCountingKind::MultiPayloadEnumGeneric)) {
132+
} else if (SWIFT_UNLIKELY(tag == RefCountingKind::MultiPayloadEnumGeneric)) {
131133
Handler::handleMultiPayloadEnumGeneric(metadata, typeLayout, offset,
132134
addrOffset,
133135
std::forward<Params>(params)...);
@@ -256,6 +258,51 @@ static void handleSinglePayloadEnumFN(const uint8_t *typeLayout, size_t &offset,
256258
}
257259
}
258260

261+
static void handleSinglePayloadEnumGeneric(const uint8_t *typeLayout,
262+
size_t &offset, uint8_t *addr,
263+
uintptr_t &addrOffset) {
264+
auto tagBytesAndOffset = readBytes<uint64_t>(typeLayout, offset);
265+
auto extraTagBytesPattern = (uint8_t)(tagBytesAndOffset >> 62);
266+
auto xiTagBytesOffset =
267+
tagBytesAndOffset & std::numeric_limits<uint32_t>::max();
268+
const Metadata *xiType = nullptr;
269+
270+
if (extraTagBytesPattern) {
271+
auto extraTagBytes = 1 << (extraTagBytesPattern - 1);
272+
auto payloadSize = readBytes<size_t>(typeLayout, offset);
273+
auto tagBytes =
274+
readTagBytes(addr + addrOffset + payloadSize, extraTagBytes);
275+
if (tagBytes) {
276+
offset += sizeof(uint64_t) + sizeof(size_t);
277+
goto noPayload;
278+
}
279+
} else {
280+
offset += sizeof(size_t);
281+
}
282+
283+
xiType = readBytes<const Metadata *>(typeLayout, offset);
284+
285+
if (xiType) {
286+
auto numEmptyCases = readBytes<unsigned>(typeLayout, offset);
287+
288+
auto tag = xiType->vw_getEnumTagSinglePayload(
289+
(const OpaqueValue *)(addr + addrOffset + xiTagBytesOffset),
290+
numEmptyCases);
291+
if (tag == 0) {
292+
offset += sizeof(size_t) * 2;
293+
return;
294+
}
295+
} else {
296+
offset += sizeof(uint64_t) + sizeof(size_t);
297+
}
298+
299+
noPayload:
300+
auto refCountBytes = readBytes<size_t>(typeLayout, offset);
301+
auto skip = readBytes<size_t>(typeLayout, offset);
302+
offset += refCountBytes;
303+
addrOffset += skip;
304+
}
305+
259306
template <typename Handler, typename... Params>
260307
static void handleMultiPayloadEnumFN(const Metadata *metadata,
261308
const uint8_t *typeLayout, size_t &offset,
@@ -363,6 +410,13 @@ struct DestroyHandler {
363410
::handleSinglePayloadEnumFN(typeLayout, offset, resolved, addr, addrOffset);
364411
}
365412

413+
static inline void handleSinglePayloadEnumGeneric(const uint8_t *typeLayout,
414+
size_t &offset,
415+
uintptr_t &addrOffset,
416+
uint8_t *addr) {
417+
::handleSinglePayloadEnumGeneric(typeLayout, offset, addr, addrOffset);
418+
}
419+
366420
static inline void handleMultiPayloadEnumFN(const Metadata *metadata,
367421
const uint8_t *typeLayout,
368422
size_t &offset, bool resolved,
@@ -466,6 +520,14 @@ struct CopyHandler {
466520
::handleSinglePayloadEnumFN(typeLayout, offset, resolved, src, addrOffset);
467521
}
468522

523+
static inline void handleSinglePayloadEnumGeneric(const uint8_t *typeLayout,
524+
size_t &offset,
525+
uintptr_t &addrOffset,
526+
uint8_t *dest,
527+
uint8_t *src) {
528+
::handleSinglePayloadEnumGeneric(typeLayout, offset, src, addrOffset);
529+
}
530+
469531
static inline void handleMultiPayloadEnumFN(const Metadata *metadata,
470532
const uint8_t *typeLayout,
471533
size_t &offset, bool resolved,
@@ -533,6 +595,14 @@ struct TakeHandler {
533595
::handleSinglePayloadEnumFN(typeLayout, offset, resolved, src, addrOffset);
534596
}
535597

598+
static inline void handleSinglePayloadEnumGeneric(const uint8_t *typeLayout,
599+
size_t &offset,
600+
uintptr_t &addrOffset,
601+
uint8_t *dest,
602+
uint8_t *src) {
603+
::handleSinglePayloadEnumGeneric(typeLayout, offset, src, addrOffset);
604+
}
605+
536606
static inline void handleMultiPayloadEnumFN(const Metadata *metadata,
537607
const uint8_t *typeLayout,
538608
size_t &offset, bool resolved,

stdlib/public/runtime/BytecodeLayouts.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ enum class RefCountingKind : uint8_t {
4646
SinglePayloadEnumSimple = 0x10,
4747
SinglePayloadEnumFN = 0x11,
4848
SinglePayloadEnumFNResolved = 0x12,
49+
SinglePayloadEnumGeneric = 0x13,
4950

50-
MultiPayloadEnumFN = 0x13,
51-
MultiPayloadEnumFNResolved = 0x14,
52-
MultiPayloadEnumGeneric = 0x15,
51+
MultiPayloadEnumFN = 0x14,
52+
MultiPayloadEnumFNResolved = 0x15,
53+
MultiPayloadEnumGeneric = 0x16,
5354

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

0 commit comments

Comments
 (0)