Skip to content

Commit fe6f8f5

Browse files
authored
[IRGen] Implement support for multi payload enums in layout strings (#66354)
* [IRGen] Implement support for multi payload enums in layout strings rdar://105837114 * Implement multi payload enum cases in swift_resolve_resilientAccessors * Add missing const
1 parent e4debda commit fe6f8f5

File tree

5 files changed

+286
-43
lines changed

5 files changed

+286
-43
lines changed

lib/IRGen/TypeLayout.cpp

Lines changed: 112 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ class LayoutStringBuilder {
7777
Resilient = 0x0f,
7878
SinglePayloadEnumSimple = 0x10,
7979
SinglePayloadEnumFN = 0x11,
80-
SinglePayloadEnumFNResolved = 0x12,
80+
// reserved
81+
// SinglePayloadEnumFNResolved = 0x12,
82+
83+
MultiPayloadEnumFN = 0x13,
84+
// reserved
85+
// MultiPayloadEnumFNResolved = 0x14,
8186

8287
Skip = 0x80,
8388
// We may use the MSB as flag that a count follows,
@@ -101,13 +106,19 @@ class LayoutStringBuilder {
101106
const TypeLayoutEntry *payload;
102107
};
103108

109+
struct MultiPayloadEnumFN {
110+
llvm::Function *tagFn;
111+
const EnumTypeLayoutEntry *entry;
112+
};
113+
104114
struct RefCounting {
105115
RefCountingKind kind;
106116
union {
107117
size_t size;
108-
llvm::Function* metaTypeRef;
118+
llvm::Function *metaTypeRef;
109119
SinglePayloadEnumSimple singlePayloadEnumSimple;
110120
SinglePayloadEnumFN singlePayloadEnumFN;
121+
MultiPayloadEnumFN multiPayloadEnumFN;
111122
};
112123

113124
RefCounting() = default;
@@ -151,6 +162,15 @@ class LayoutStringBuilder {
151162
refCountings.push_back(op);
152163
}
153164

165+
void addMultiPayloadEnumFN(llvm::Function *tagFn,
166+
const EnumTypeLayoutEntry *entry) {
167+
RefCounting op;
168+
op.kind = RefCountingKind::MultiPayloadEnumFN;
169+
op.multiPayloadEnumFN.tagFn = tagFn;
170+
op.multiPayloadEnumFN.entry = entry;
171+
refCountings.push_back(op);
172+
}
173+
154174
void addSkip(size_t size) {
155175
if (refCountings.empty() ||
156176
refCountings.back().kind != RefCountingKind::Skip) {
@@ -280,6 +300,63 @@ class LayoutStringBuilder {
280300
break;
281301
}
282302

303+
case RefCountingKind::MultiPayloadEnumFN: {
304+
uint64_t op = (static_cast<uint64_t>(refCounting.kind) << 56) | skip;
305+
B.addInt64(op);
306+
307+
skip = 0;
308+
309+
auto enumData = refCounting.multiPayloadEnumFN;
310+
auto payloads = enumData.entry->cases;
311+
312+
B.addRelativeOffset(IGM.IntPtrTy, enumData.tagFn);
313+
314+
B.addSize(Size(payloads.size()));
315+
316+
auto nestedRefCountBytesPlaceholder =
317+
B.addPlaceholderWithSize(IGM.SizeTy);
318+
B.addSize(*enumData.entry->fixedSize(IGM));
319+
320+
SmallVector<
321+
clang::CodeGen::ConstantAggregateBuilderBase::PlaceholderPosition,
322+
4>
323+
offsetPlaceholders;
324+
for (auto *p : payloads) {
325+
(void)p;
326+
auto placeholder = B.addPlaceholderWithSize(IGM.SizeTy);
327+
offsetPlaceholders.push_back(placeholder);
328+
refCountBytes += IGM.getPointerSize().getValue();
329+
}
330+
331+
size_t nestedRefCountBytes = 0;
332+
for (auto p : llvm::zip(payloads, offsetPlaceholders)) {
333+
auto *payload = std::get<0>(p);
334+
335+
B.fillPlaceholderWithInt(std::get<1>(p), IGM.SizeTy,
336+
nestedRefCountBytes);
337+
338+
size_t nestedSkip = 0;
339+
LayoutStringBuilder nestedBuilder{};
340+
payload->refCountString(IGM, nestedBuilder, genericSig);
341+
addRefCountings(IGM, B, genericSig, nestedBuilder.refCountings,
342+
nestedSkip, nestedRefCountBytes, flags);
343+
344+
// NUL terminator
345+
B.addInt64(0);
346+
nestedRefCountBytes += sizeof(uint64_t);
347+
}
348+
349+
B.fillPlaceholderWithInt(nestedRefCountBytesPlaceholder, IGM.SizeTy,
350+
nestedRefCountBytes);
351+
352+
refCountBytes += sizeof(uint64_t) +
353+
(4 * IGM.getPointerSize().getValue()) +
354+
nestedRefCountBytes;
355+
356+
flags |= LayoutStringFlags::HasRelativePointers;
357+
break;
358+
}
359+
283360
default: {
284361
uint64_t op = (static_cast<uint64_t>(refCounting.kind) << 56) | skip;
285362
B.addInt64(op);
@@ -2208,6 +2285,22 @@ bool EnumTypeLayoutEntry::buildSinglePayloadRefCountString(
22082285
return true;
22092286
}
22102287

2288+
bool EnumTypeLayoutEntry::buildMultiPayloadRefCountString(
2289+
IRGenModule &IGM, LayoutStringBuilder &B,
2290+
GenericSignature genericSig) const {
2291+
auto valid = std::all_of(cases.begin(), cases.end(), [&](auto *c) {
2292+
LayoutStringBuilder nestedBuilder{};
2293+
return c->refCountString(IGM, nestedBuilder, genericSig);
2294+
});
2295+
2296+
if (valid) {
2297+
auto *tagFn = createFixedEnumLoadTag(IGM, *this);
2298+
B.addMultiPayloadEnumFN(tagFn, this);
2299+
}
2300+
2301+
return valid;
2302+
}
2303+
22112304
llvm::Constant *
22122305
EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
22132306
GenericSignature genericSig) const {
@@ -2245,12 +2338,20 @@ EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
22452338
return nullptr;
22462339

22472340
case CopyDestroyStrategy::Normal: {
2248-
if (!isFixedSize(IGM) || isMultiPayloadEnum() ||
2249-
!buildSinglePayloadRefCountString(IGM, B, genericSig)) {
2250-
return *(_layoutString = llvm::Optional<llvm::Constant *>(nullptr));
2341+
bool valid = false;
2342+
if (isFixedSize(IGM)) {
2343+
if (isMultiPayloadEnum()) {
2344+
valid = buildMultiPayloadRefCountString(IGM, B, genericSig);
2345+
} else {
2346+
valid = buildSinglePayloadRefCountString(IGM, B, genericSig);
2347+
}
22512348
}
22522349

2253-
return createConstant(B);
2350+
if (valid) {
2351+
return createConstant(B);
2352+
} else {
2353+
return *(_layoutString = llvm::Optional<llvm::Constant *>(nullptr));
2354+
}
22542355
}
22552356

22562357
case CopyDestroyStrategy::ForwardToPayload:
@@ -2281,8 +2382,11 @@ bool EnumTypeLayoutEntry::refCountString(IRGenModule &IGM,
22812382
case CopyDestroyStrategy::ForwardToPayload:
22822383
return cases[0]->refCountString(IGM, B, genericSig);
22832384
case CopyDestroyStrategy::Normal: {
2284-
if (!isMultiPayloadEnum() &&
2285-
buildSinglePayloadRefCountString(IGM, B, genericSig)) {
2385+
2386+
if (isMultiPayloadEnum() &&
2387+
buildMultiPayloadRefCountString(IGM, B, genericSig)) {
2388+
return true;
2389+
} else if (buildSinglePayloadRefCountString(IGM, B, genericSig)) {
22862390
return true;
22872391
}
22882392

lib/IRGen/TypeLayout.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,9 @@ class EnumTypeLayoutEntry : public TypeLayoutEntry,
651651
LayoutStringBuilder &B,
652652
GenericSignature genericSig) const;
653653

654+
bool buildMultiPayloadRefCountString(IRGenModule &IGM, LayoutStringBuilder &B,
655+
GenericSignature genericSig) const;
656+
654657
static bool classof(const TypeLayoutEntry *entry);
655658
};
656659

0 commit comments

Comments
 (0)