Skip to content

Commit 253d8fb

Browse files
authored
[IRGen+Runtime] Add getEnumTag for layout strings on generic single payload enum (swiftlang#66911)
1 parent 98d895d commit 253d8fb

File tree

6 files changed

+82
-1
lines changed

6 files changed

+82
-1
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,16 @@ FUNCTION(MultiPayloadEnumGenericGetEnumTag,
23352335
ATTRS(NoUnwind),
23362336
EFFECT(NoEffect))
23372337

2338+
// unsigned swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
2339+
// const Metadata *metadata);
2340+
FUNCTION(SinglePayloadEnumGenericGetEnumTag,
2341+
swift_singlePayloadEnumGeneric_getEnumTag,
2342+
C_CC, AlwaysAvailable,
2343+
RETURNS(Int32Ty),
2344+
ARGS(Int8PtrTy, TypeMetadataPtrTy),
2345+
ATTRS(NoUnwind),
2346+
EFFECT(NoEffect))
2347+
23382348
// void swift_generic_instantiateLayoutString(const uint8_t* layoutStr,
23392349
// Metadata* type);
23402350
FUNCTION(GenericInstantiateLayoutString,

lib/IRGen/GenValueWitness.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ static llvm::Constant *getEnumTagFunction(IRGenModule &IGM,
908908
return IGM.getMultiPayloadEnumGenericGetEnumTagFn();
909909
} else {
910910
// TODO: implement support for single payload generic enums
911-
return nullptr;
911+
return IGM.getSinglePayloadEnumGenericGetEnumTagFn();
912912
}
913913
} else if (typeLayoutEntry->isMultiPayloadEnum()) {
914914
return IGM.getEnumFnGetEnumTagFn();

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,51 @@ swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
692692
}
693693
}
694694

695+
extern "C" unsigned
696+
swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
697+
const Metadata *metadata) {
698+
auto addr = reinterpret_cast<const uint8_t *>(address);
699+
LayoutStringReader reader{metadata->getLayoutString(),
700+
layoutStringHeaderSize + sizeof(uint64_t)};
701+
702+
auto tagBytesAndOffset = reader.readBytes<uint64_t>();
703+
auto extraTagBytesPattern = (uint8_t)(tagBytesAndOffset >> 62);
704+
auto xiTagBytesOffset =
705+
tagBytesAndOffset & std::numeric_limits<uint32_t>::max();
706+
const Metadata *xiType = nullptr;
707+
708+
if (extraTagBytesPattern) {
709+
auto extraTagBytes = 1 << (extraTagBytesPattern - 1);
710+
auto payloadSize = reader.readBytes<size_t>();
711+
auto tagBytes = readTagBytes(addr + payloadSize, extraTagBytes);
712+
if (tagBytes) {
713+
xiType = reader.readBytes<const Metadata *>();
714+
unsigned payloadNumExtraInhabitants =
715+
xiType ? xiType->vw_getNumExtraInhabitants() : 0;
716+
unsigned caseIndexFromExtraTagBits =
717+
payloadSize >= 4 ? 0 : (tagBytes - 1U) << (payloadSize * 8U);
718+
unsigned caseIndexFromValue = loadEnumElement(addr, payloadSize);
719+
unsigned noPayloadIndex =
720+
(caseIndexFromExtraTagBits | caseIndexFromValue) +
721+
payloadNumExtraInhabitants;
722+
return noPayloadIndex + 1;
723+
}
724+
} else {
725+
reader.skip(sizeof(size_t));
726+
}
727+
728+
xiType = reader.readBytes<const Metadata *>();
729+
730+
if (xiType) {
731+
auto numEmptyCases = reader.readBytes<unsigned>();
732+
733+
return xiType->vw_getEnumTagSinglePayload(
734+
(const OpaqueValue *)(addr + xiTagBytesOffset), numEmptyCases);
735+
}
736+
737+
return 0;
738+
}
739+
695740
void swift::swift_resolve_resilientAccessors(uint8_t *layoutStr,
696741
size_t layoutStrOffset,
697742
const uint8_t *fieldLayoutStr,

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ SWIFT_RUNTIME_EXPORT
119119
unsigned swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
120120
const Metadata *metadata);
121121
SWIFT_RUNTIME_EXPORT
122+
unsigned swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
123+
const Metadata *metadata);
124+
SWIFT_RUNTIME_EXPORT
122125
void swift_generic_instantiateLayoutString(const uint8_t *layoutStr,
123126
Metadata *type);
124127

test/Interpreter/Inputs/layout_string_witnesses_types_resilient.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ public struct GenericResilient<C, T> {
1919
}
2020
}
2121

22+
public enum ResilientSinglePayloadEnumGeneric<T> {
23+
case empty0
24+
case empty1
25+
case nonEmpty0(T)
26+
}
27+
2228
public enum ResilientMultiPayloadEnumGeneric<T> {
2329
case empty0
2430
case empty1
@@ -39,6 +45,10 @@ public enum ResilientSinglePayloadEnumComplex {
3945
case nonEmpty(ResilientMultiPayloadEnum)
4046
}
4147

48+
public func getResilientSinglePayloadEnumGenericEmpty0<T>(_ t: T.Type) -> ResilientSinglePayloadEnumGeneric<T> {
49+
return .empty0
50+
}
51+
4252
public func getResilientMultiPayloadEnumGenericEmpty0<T>(_ t: T.Type) -> ResilientMultiPayloadEnumGeneric<T> {
4353
return .empty0
4454
}

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,19 @@ func testResilientMultiPayloadEnumTag() {
543543

544544
testResilientMultiPayloadEnumTag()
545545

546+
func testResilientSinglePayloadEnumGenericTag() {
547+
let x = switch getResilientSinglePayloadEnumGenericEmpty0(AnyObject.self) {
548+
case .nonEmpty0: 0
549+
case .empty0: 1
550+
case .empty1: 2
551+
}
552+
553+
// CHECK: Enum case: 1
554+
print("Enum case: \(x)")
555+
}
556+
557+
testResilientSinglePayloadEnumGenericTag()
558+
546559
func testResilientMultiPayloadEnumGenericTag() {
547560
let x = switch getResilientMultiPayloadEnumGenericEmpty0(AnyObject.self) {
548561
case .nonEmpty0: 0

0 commit comments

Comments
 (0)