@@ -77,7 +77,12 @@ class LayoutStringBuilder {
77
77
Resilient = 0x0f ,
78
78
SinglePayloadEnumSimple = 0x10 ,
79
79
SinglePayloadEnumFN = 0x11 ,
80
- SinglePayloadEnumFNResolved = 0x12 ,
80
+ // reserved
81
+ // SinglePayloadEnumFNResolved = 0x12,
82
+
83
+ MultiPayloadEnumFN = 0x13 ,
84
+ // reserved
85
+ // MultiPayloadEnumFNResolved = 0x14,
81
86
82
87
Skip = 0x80 ,
83
88
// We may use the MSB as flag that a count follows,
@@ -101,13 +106,19 @@ class LayoutStringBuilder {
101
106
const TypeLayoutEntry *payload;
102
107
};
103
108
109
+ struct MultiPayloadEnumFN {
110
+ llvm::Function *tagFn;
111
+ const EnumTypeLayoutEntry *entry;
112
+ };
113
+
104
114
struct RefCounting {
105
115
RefCountingKind kind;
106
116
union {
107
117
size_t size;
108
- llvm::Function* metaTypeRef;
118
+ llvm::Function * metaTypeRef;
109
119
SinglePayloadEnumSimple singlePayloadEnumSimple;
110
120
SinglePayloadEnumFN singlePayloadEnumFN;
121
+ MultiPayloadEnumFN multiPayloadEnumFN;
111
122
};
112
123
113
124
RefCounting () = default ;
@@ -151,6 +162,15 @@ class LayoutStringBuilder {
151
162
refCountings.push_back (op);
152
163
}
153
164
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
+
154
174
void addSkip (size_t size) {
155
175
if (refCountings.empty () ||
156
176
refCountings.back ().kind != RefCountingKind::Skip) {
@@ -280,6 +300,63 @@ class LayoutStringBuilder {
280
300
break ;
281
301
}
282
302
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
+
283
360
default : {
284
361
uint64_t op = (static_cast <uint64_t >(refCounting.kind ) << 56 ) | skip;
285
362
B.addInt64 (op);
@@ -2208,6 +2285,22 @@ bool EnumTypeLayoutEntry::buildSinglePayloadRefCountString(
2208
2285
return true ;
2209
2286
}
2210
2287
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
+
2211
2304
llvm::Constant *
2212
2305
EnumTypeLayoutEntry::layoutString (IRGenModule &IGM,
2213
2306
GenericSignature genericSig) const {
@@ -2245,12 +2338,20 @@ EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
2245
2338
return nullptr ;
2246
2339
2247
2340
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
+ }
2251
2348
}
2252
2349
2253
- return createConstant (B);
2350
+ if (valid) {
2351
+ return createConstant (B);
2352
+ } else {
2353
+ return *(_layoutString = llvm::Optional<llvm::Constant *>(nullptr ));
2354
+ }
2254
2355
}
2255
2356
2256
2357
case CopyDestroyStrategy::ForwardToPayload:
@@ -2281,8 +2382,11 @@ bool EnumTypeLayoutEntry::refCountString(IRGenModule &IGM,
2281
2382
case CopyDestroyStrategy::ForwardToPayload:
2282
2383
return cases[0 ]->refCountString (IGM, B, genericSig);
2283
2384
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)) {
2286
2390
return true ;
2287
2391
}
2288
2392
0 commit comments