Skip to content

Commit 36ddb77

Browse files
authored
[IRGen+Runtime] Layout string getEnumTag for generic multi payload enums (#66872)
We already store all necessary information to extract the tag in the layout string, so we should utilize it for the getEnumTag witness
1 parent 8d4a51b commit 36ddb77

File tree

6 files changed

+109
-9
lines changed

6 files changed

+109
-9
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_multiPayloadEnumGeneric_getEnumTag(opaque* address,
2319+
// const Metadata *type);
2320+
FUNCTION(MultiPayloadEnumGenericGetEnumTag,
2321+
swift_multiPayloadEnumGeneric_getEnumTag,
2322+
C_CC, AlwaysAvailable,
2323+
RETURNS(Int32Ty),
2324+
ARGS(Int8PtrTy, TypeMetadataPtrTy),
2325+
ATTRS(NoUnwind),
2326+
EFFECT(NoEffect))
2327+
23182328
// void swift_generic_instantiateLayoutString(const uint8_t* layoutStr, Metadata* type);
23192329
FUNCTION(GenericInstantiateLayoutString,
23202330
swift_generic_instantiateLayoutString,

lib/IRGen/GenValueWitness.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,29 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
11131113
goto standard;
11141114
}
11151115

1116-
case ValueWitness::GetEnumTag:
1116+
case ValueWitness::GetEnumTag: {
1117+
assert(concreteType.getEnumOrBoundGenericEnum());
1118+
1119+
if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) &&
1120+
IGM.getOptions().EnableLayoutStringValueWitnesses) {
1121+
auto ty = boundGenericCharacteristics
1122+
? boundGenericCharacteristics->concreteType
1123+
: concreteType;
1124+
auto &typeInfo = boundGenericCharacteristics
1125+
? *boundGenericCharacteristics->TI
1126+
: concreteTI;
1127+
if (auto *typeLayoutEntry = typeInfo.buildTypeLayoutEntry(
1128+
IGM, ty, /*useStructLayouts*/ true)) {
1129+
if (auto *enumLayoutEntry = typeLayoutEntry->getAsEnum()) {
1130+
if (enumLayoutEntry->isMultiPayloadEnum() &&
1131+
!typeLayoutEntry->isFixedSize(IGM)) {
1132+
return addFunction(IGM.getMultiPayloadEnumGenericGetEnumTagFn());
1133+
}
1134+
}
1135+
}
1136+
}
1137+
goto standard;
1138+
}
11171139
case ValueWitness::DestructiveProjectEnumData:
11181140
case ValueWitness::DestructiveInjectEnumTag:
11191141
assert(concreteType.getEnumOrBoundGenericEnum());

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "BytecodeLayouts.h"
2020
#include "../SwiftShims/swift/shims/HeapObject.h"
21+
#include "EnumImpl.h"
2122
#include "WeakReference.h"
2223
#include "swift/ABI/MetadataValues.h"
2324
#include "swift/ABI/System.h"
@@ -160,7 +161,7 @@ inline static void handleRefCounts(const Metadata *metadata, Params... params) {
160161
std::forward<Params>(params)...);
161162
}
162163

163-
static uint64_t readTagBytes(uint8_t *addr, uint8_t byteCount) {
164+
static uint64_t readTagBytes(const uint8_t *addr, uint8_t byteCount) {
164165
switch (byteCount) {
165166
case 1:
166167
return addr[0];
@@ -651,6 +652,35 @@ swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src,
651652
return swift_generic_initWithTake(dest, src, metadata);
652653
}
653654

655+
extern "C" unsigned
656+
swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
657+
const Metadata *metadata) {
658+
auto addr = reinterpret_cast<const uint8_t *>(address);
659+
LayoutStringReader reader{metadata->getLayoutString(),
660+
layoutStringHeaderSize + sizeof(uint64_t)};
661+
662+
auto tagBytes = reader.readBytes<size_t>();
663+
auto numPayloads = reader.readBytes<size_t>();
664+
reader.skip(sizeof(size_t));
665+
auto enumSize = reader.readBytes<size_t>();
666+
auto payloadSize = enumSize - tagBytes;
667+
668+
auto enumTag = (unsigned)readTagBytes(addr + payloadSize, tagBytes);
669+
if (enumTag < numPayloads) {
670+
return enumTag;
671+
}
672+
673+
auto payloadValue = loadEnumElement(addr, payloadSize);
674+
675+
if (payloadSize >= 4) {
676+
return numPayloads + payloadValue;
677+
} else {
678+
unsigned numPayloadBits = payloadSize * CHAR_BIT;
679+
return (payloadValue | (enumTag - numPayloads) << numPayloadBits) +
680+
numPayloads;
681+
}
682+
}
683+
654684
void swift::swift_resolve_resilientAccessors(uint8_t *layoutStr,
655685
size_t layoutStrOffset,
656686
const uint8_t *fieldLayoutStr,

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,30 @@ struct LayoutStringWriter {
9494
};
9595

9696
SWIFT_RUNTIME_EXPORT
97-
void swift_generic_destroy(swift::OpaqueValue *address, const Metadata *metadata);
97+
void swift_generic_destroy(swift::OpaqueValue *address,
98+
const Metadata *metadata);
9899
SWIFT_RUNTIME_EXPORT
99-
swift::OpaqueValue *swift_generic_assignWithCopy(swift::OpaqueValue *dest, swift::OpaqueValue *src, const Metadata *metadata);
100+
swift::OpaqueValue *swift_generic_assignWithCopy(swift::OpaqueValue *dest,
101+
swift::OpaqueValue *src,
102+
const Metadata *metadata);
100103
SWIFT_RUNTIME_EXPORT
101-
swift::OpaqueValue *swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src, const Metadata *metadata);
104+
swift::OpaqueValue *swift_generic_assignWithTake(swift::OpaqueValue *dest,
105+
swift::OpaqueValue *src,
106+
const Metadata *metadata);
102107
SWIFT_RUNTIME_EXPORT
103-
swift::OpaqueValue *swift_generic_initWithCopy(swift::OpaqueValue *dest, swift::OpaqueValue *src, const Metadata *metadata);
108+
swift::OpaqueValue *swift_generic_initWithCopy(swift::OpaqueValue *dest,
109+
swift::OpaqueValue *src,
110+
const Metadata *metadata);
104111
SWIFT_RUNTIME_EXPORT
105-
swift::OpaqueValue *swift_generic_initWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src, const Metadata *metadata);
112+
swift::OpaqueValue *swift_generic_initWithTake(swift::OpaqueValue *dest,
113+
swift::OpaqueValue *src,
114+
const Metadata *metadata);
106115
SWIFT_RUNTIME_EXPORT
107-
void swift_generic_instantiateLayoutString(const uint8_t *layoutStr, Metadata *type);
116+
unsigned swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
117+
const Metadata *metadata);
118+
SWIFT_RUNTIME_EXPORT
119+
void swift_generic_instantiateLayoutString(const uint8_t *layoutStr,
120+
Metadata *type);
108121

109122
void swift_resolve_resilientAccessors(uint8_t *layoutStr,
110123
size_t layoutStrOffset,

test/Interpreter/Inputs/layout_string_witnesses_types_resilient.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,15 @@ public struct GenericResilient<C, T> {
1717
self.x = x
1818
self.y = y
1919
}
20-
}
20+
}
21+
22+
public enum ResilientMultiPayloadEnum<T> {
23+
case empty0
24+
case empty1
25+
case nonEmpty0(AnyObject)
26+
case nonEmpty1(T)
27+
}
28+
29+
public func getResilientMultiPayloadEnumEmpty0<T>(_ t: T.Type) -> ResilientMultiPayloadEnum<T> {
30+
return .empty0
31+
}

test/Interpreter/layout_string_witnesses_dynamic.swift

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

517517
testGenericSinglePayloadEnumManyXI()
518518

519+
func testResilientMultiPayloadEnumTag() {
520+
let x = switch getResilientMultiPayloadEnumEmpty0(AnyObject.self) {
521+
case .nonEmpty0: 0
522+
case .nonEmpty1: 1
523+
case .empty0: 2
524+
case .empty1: 3
525+
}
526+
527+
// CHECK: Enum case: 2
528+
print("Enum case: \(x)")
529+
}
530+
531+
testResilientMultiPayloadEnumTag()
532+
519533
#if os(macOS)
520534

521535
import Foundation

0 commit comments

Comments
 (0)