@@ -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+
22112304llvm::Constant *
22122305EnumTypeLayoutEntry::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
0 commit comments