Skip to content

Commit fc6834d

Browse files
authored
[IRGen+Runtime] Add getEnumTag for layout strings on simple single payload enums (#66941)
1 parent 75656a9 commit fc6834d

File tree

6 files changed

+92
-4
lines changed

6 files changed

+92
-4
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,16 @@ FUNCTION(GenericInitWithTake,
23152315
ATTRS(NoUnwind),
23162316
EFFECT(Refcounting))
23172317

2318+
// unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address,
2319+
// const Metadata *metadata);
2320+
FUNCTION(EnumSimpleGetEnumTag,
2321+
swift_enumSimple_getEnumTag,
2322+
C_CC, AlwaysAvailable,
2323+
RETURNS(Int32Ty),
2324+
ARGS(Int8PtrTy, TypeMetadataPtrTy),
2325+
ATTRS(NoUnwind),
2326+
EFFECT(NoEffect))
2327+
23182328
// unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address,
23192329
// const Metadata *metadata);
23202330
FUNCTION(EnumFnGetEnumTag,

lib/IRGen/GenValueWitness.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,8 +900,11 @@ static bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM,
900900
}
901901

902902
static llvm::Constant *getEnumTagFunction(IRGenModule &IGM,
903-
const EnumTypeLayoutEntry *typeLayoutEntry) {
904-
if (typeLayoutEntry->isSingleton()) {
903+
const EnumTypeLayoutEntry *typeLayoutEntry,
904+
GenericSignature genericSig) {
905+
if (!typeLayoutEntry->layoutString(IGM, genericSig) &&
906+
!isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry) ||
907+
typeLayoutEntry->isSingleton()) {
905908
return nullptr;
906909
} else if (!typeLayoutEntry->isFixedSize(IGM)) {
907910
if (typeLayoutEntry->isMultiPayloadEnum()) {
@@ -923,7 +926,7 @@ static llvm::Constant *getEnumTagFunction(IRGenModule &IGM,
923926
(tzCount % toCount != 0))) {
924927
return IGM.getEnumFnGetEnumTagFn();
925928
} else {
926-
return nullptr;
929+
return IGM.getEnumSimpleGetEnumTagFn();
927930
}
928931
}
929932
}
@@ -1156,7 +1159,9 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
11561159
if (auto *typeLayoutEntry = typeInfo.buildTypeLayoutEntry(
11571160
IGM, ty, /*useStructLayouts*/ true)) {
11581161
if (auto *enumLayoutEntry = typeLayoutEntry->getAsEnum()) {
1159-
if (auto *fn = getEnumTagFunction(IGM, enumLayoutEntry)) {
1162+
auto genericSig = concreteType.getNominalOrBoundGenericNominal()
1163+
->getGenericSignature();
1164+
if (auto *fn = getEnumTagFunction(IGM, enumLayoutEntry, genericSig)) {
11601165
return addFunction(fn);
11611166
}
11621167
}

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,53 @@ swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src,
652652
return swift_generic_initWithTake(dest, src, metadata);
653653
}
654654

655+
extern "C"
656+
unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address,
657+
const Metadata *metadata) {
658+
auto addr = reinterpret_cast<uint8_t *>(address);
659+
LayoutStringReader reader{metadata->getLayoutString(),
660+
layoutStringHeaderSize + sizeof(uint64_t)};
661+
auto byteCountsAndOffset = reader.readBytes<uint64_t>();
662+
auto extraTagBytesPattern = (uint8_t)(byteCountsAndOffset >> 62);
663+
auto xiTagBytesPattern = ((uint8_t)(byteCountsAndOffset >> 59)) & 0x7;
664+
auto xiTagBytesOffset =
665+
byteCountsAndOffset & std::numeric_limits<uint32_t>::max();
666+
667+
if (extraTagBytesPattern) {
668+
auto extraTagBytes = 1 << (extraTagBytesPattern - 1);
669+
auto payloadSize = reader.readBytes<size_t>();
670+
auto tagBytes = readTagBytes(addr + payloadSize, extraTagBytes);
671+
if (tagBytes) {
672+
reader.skip(sizeof(uint64_t));
673+
auto payloadNumExtraInhabitants = reader.readBytes<size_t>();
674+
unsigned caseIndexFromExtraTagBits =
675+
payloadSize >= 4 ? 0 : (tagBytes - 1U) << (payloadSize * 8U);
676+
unsigned caseIndexFromValue = loadEnumElement(addr, payloadSize);
677+
unsigned noPayloadIndex =
678+
(caseIndexFromExtraTagBits | caseIndexFromValue) +
679+
payloadNumExtraInhabitants;
680+
return noPayloadIndex + 1;
681+
}
682+
} else {
683+
reader.skip(sizeof(size_t));
684+
}
685+
686+
if (xiTagBytesPattern) {
687+
auto zeroTagValue = reader.readBytes<uint64_t>();
688+
auto xiTagValues = reader.readBytes<size_t>();
689+
690+
auto xiTagBytes = 1 << (xiTagBytesPattern - 1);
691+
uint64_t tagBytes =
692+
readTagBytes(addr + xiTagBytesOffset, xiTagBytes) -
693+
zeroTagValue;
694+
if (tagBytes < xiTagValues) {
695+
return tagBytes + 1;
696+
}
697+
}
698+
699+
return 0;
700+
}
701+
655702
extern "C"
656703
unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address,
657704
const Metadata *metadata) {

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ swift::OpaqueValue *swift_generic_initWithTake(swift::OpaqueValue *dest,
113113
swift::OpaqueValue *src,
114114
const Metadata *metadata);
115115
SWIFT_RUNTIME_EXPORT
116+
unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address,
117+
const Metadata *metadata);
118+
SWIFT_RUNTIME_EXPORT
116119
unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address,
117120
const Metadata *metadata);
118121
SWIFT_RUNTIME_EXPORT

test/Interpreter/Inputs/layout_string_witnesses_types_resilient.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ public enum ResilientSinglePayloadEnumComplex {
4545
case nonEmpty(ResilientMultiPayloadEnum)
4646
}
4747

48+
public enum ResilientSinglePayloadEnumSimple {
49+
case empty0
50+
case empty1
51+
case nonEmpty(AnyObject)
52+
}
53+
4854
public func getResilientSinglePayloadEnumGenericEmpty0<T>(_ t: T.Type) -> ResilientSinglePayloadEnumGeneric<T> {
4955
return .empty0
5056
}
@@ -60,3 +66,7 @@ public func getResilientMultiPayloadEnumEmpty0() -> ResilientMultiPayloadEnum {
6066
public func getResilientSinglePayloadEnumComplexEmpty0() -> ResilientSinglePayloadEnumComplex {
6167
return .empty0
6268
}
69+
70+
public func getResilientSinglePayloadEnumSimpleEmpty0() -> ResilientSinglePayloadEnumSimple {
71+
return .empty0
72+
}

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,19 @@ func testGenericSinglePayloadEnumManyXI() {
516516

517517
testGenericSinglePayloadEnumManyXI()
518518

519+
func testResilientSinglePayloadEnumSimpleTag() {
520+
let x = switch getResilientSinglePayloadEnumSimpleEmpty0() {
521+
case .nonEmpty: 0
522+
case .empty0: 1
523+
case .empty1: 2
524+
}
525+
526+
// CHECK: Enum case: 1
527+
print("Enum case: \(x)")
528+
}
529+
530+
testResilientSinglePayloadEnumSimpleTag()
531+
519532
func testResilientSinglePayloadEnumComplexTag() {
520533
let x = switch getResilientSinglePayloadEnumComplexEmpty0() {
521534
case .nonEmpty: 0

0 commit comments

Comments
 (0)