Skip to content

Commit 36914d9

Browse files
authored
Merge pull request #67039 from drexin/wip-mp-gen-destr-inject-tag
Support destructiveInjectEnumTag in generic multi payload enums with layout strings
2 parents cdcba01 + 707330c commit 36914d9

File tree

5 files changed

+81
-3
lines changed

5 files changed

+81
-3
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,17 @@ FUNCTION(MultiPayloadEnumGenericGetEnumTag,
23662366
ATTRS(NoUnwind, WillReturn),
23672367
EFFECT(NoEffect))
23682368

2369+
// void swift_multiPayloadEnumGeneric_destructiveInjectEnumTag(swift::OpaqueValue *address,
2370+
// unsigned tag,
2371+
// const Metadata *metadata)
2372+
FUNCTION(MultiPayloadEnumGenericDestructiveInjectEnumTag,
2373+
swift_multiPayloadEnumGeneric_destructiveInjectEnumTag,
2374+
C_CC, AlwaysAvailable,
2375+
RETURNS(VoidTy),
2376+
ARGS(Int8PtrTy, Int32Ty, TypeMetadataPtrTy),
2377+
ATTRS(NoUnwind, WillReturn),
2378+
EFFECT(NoEffect))
2379+
23692380
// unsigned swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
23702381
// const Metadata *metadata);
23712382
FUNCTION(SinglePayloadEnumGenericGetEnumTag,

lib/IRGen/GenValueWitness.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -937,12 +937,13 @@ getDestructiveInjectEnumTagFunction(IRGenModule &IGM,
937937
const EnumTypeLayoutEntry *typeLayoutEntry,
938938
GenericSignature genericSig) {
939939
if ((!typeLayoutEntry->layoutString(IGM, genericSig) &&
940-
!isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) ||
941-
typeLayoutEntry->isSingleton()) {
940+
!isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry))) {
941+
return nullptr;
942+
} else if (typeLayoutEntry->isSingleton()) {
942943
return nullptr;
943944
} else if (!typeLayoutEntry->isFixedSize(IGM)) {
944945
if (typeLayoutEntry->isMultiPayloadEnum()) {
945-
return nullptr;
946+
return IGM.getMultiPayloadEnumGenericDestructiveInjectEnumTagFn();
946947
} else {
947948
return IGM.getSinglePayloadEnumGenericDestructiveInjectEnumTagFn();
948949
}

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,41 @@ swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
746746
}
747747
}
748748

749+
extern "C" void swift_multiPayloadEnumGeneric_destructiveInjectEnumTag(
750+
swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) {
751+
auto addr = reinterpret_cast<uint8_t *>(address);
752+
LayoutStringReader reader{metadata->getLayoutString(),
753+
layoutStringHeaderSize + sizeof(uint64_t)};
754+
755+
auto numTagBytes = reader.readBytes<size_t>();
756+
auto numPayloads = reader.readBytes<size_t>();
757+
reader.skip(sizeof(size_t));
758+
auto enumSize = reader.readBytes<size_t>();
759+
auto payloadSize = enumSize - numTagBytes;
760+
761+
if (tag < numPayloads) {
762+
// For a payload case, store the tag after the payload area.
763+
auto tagBytes = addr + payloadSize;
764+
storeEnumElement(tagBytes, tag, numTagBytes);
765+
} else {
766+
// For an empty case, factor out the parts that go in the payload and
767+
// tag areas.
768+
unsigned whichEmptyCase = tag - numPayloads;
769+
unsigned whichTag, whichPayloadValue;
770+
if (payloadSize >= 4) {
771+
whichTag = numPayloads;
772+
whichPayloadValue = whichEmptyCase;
773+
} else {
774+
unsigned numPayloadBits = payloadSize * CHAR_BIT;
775+
whichTag = numPayloads + (whichEmptyCase >> numPayloadBits);
776+
whichPayloadValue = whichEmptyCase & ((1U << numPayloadBits) - 1U);
777+
}
778+
auto tagBytes = addr + payloadSize;
779+
storeEnumElement(tagBytes, whichTag, numTagBytes);
780+
storeEnumElement(addr, whichPayloadValue, payloadSize);
781+
}
782+
}
783+
749784
template <typename T>
750785
static inline T handleSinglePayloadEnumGenericTag(
751786
LayoutStringReader &reader, uint8_t *addr,

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ SWIFT_RUNTIME_EXPORT
130130
unsigned swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
131131
const Metadata *metadata);
132132
SWIFT_RUNTIME_EXPORT
133+
void swift_multiPayloadEnumGeneric_destructiveInjectEnumTag(
134+
swift::OpaqueValue *address, unsigned tag, const Metadata *metadata);
135+
SWIFT_RUNTIME_EXPORT
133136
unsigned swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
134137
const Metadata *metadata);
135138
SWIFT_RUNTIME_EXPORT

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,34 @@ func testResilientSinglePayloadEnumGenericInjectTag() {
618618

619619
testResilientSinglePayloadEnumGenericInjectTag()
620620

621+
@inline(never)
622+
func matchResilientMultiPayloadEnumGenericTag(_ x: ResilientMultiPayloadEnumGeneric<AnyObject>) -> Int {
623+
return switch x {
624+
case .nonEmpty0: 0
625+
case .nonEmpty1: 1
626+
case .empty0: 2
627+
case .empty1: 3
628+
}
629+
}
630+
631+
func testResilientMultiPayloadEnumGenericInjectTag() {
632+
let x = ResilientMultiPayloadEnumGeneric<AnyObject>.nonEmpty0(SimpleClass(x: 23))
633+
let y = ResilientMultiPayloadEnumGeneric<AnyObject>.nonEmpty1(SimpleClass(x: 32))
634+
let z = ResilientMultiPayloadEnumGeneric<AnyObject>.empty0
635+
let w = ResilientMultiPayloadEnumGeneric<AnyObject>.empty1
636+
637+
// CHECK: Enum case: 0
638+
print("Enum case: \(matchResilientMultiPayloadEnumGenericTag(x))")
639+
// CHECK: Enum case: 1
640+
print("Enum case: \(matchResilientMultiPayloadEnumGenericTag(y))")
641+
// CHECK: Enum case: 2
642+
print("Enum case: \(matchResilientMultiPayloadEnumGenericTag(z))")
643+
// CHECK: Enum case: 3
644+
print("Enum case: \(matchResilientMultiPayloadEnumGenericTag(w))")
645+
}
646+
647+
testResilientMultiPayloadEnumGenericInjectTag()
648+
621649
#if os(macOS)
622650

623651
import Foundation

0 commit comments

Comments
 (0)