@@ -83,20 +83,20 @@ TypeSubElementCount::TypeSubElementCount(SILType type, SILModule &mod,
83
83
return ;
84
84
}
85
85
86
- // If we have an enum, we add one for tracking if the base enum is set and use
87
- // the remaining bits for the max sized payload. This ensures that if we have
88
- // a smaller sized payload, we still get all of the bits set, allowing for a
89
- // homogeneous representation.
90
86
if (auto *enumDecl = type.getEnumOrBoundGenericEnum ()) {
91
87
unsigned numElements = 0 ;
92
88
for (auto *eltDecl : enumDecl->getAllElements ()) {
93
89
if (!eltDecl->hasAssociatedValues ())
94
90
continue ;
95
91
auto elt = type.getEnumElementType (eltDecl, mod, context);
96
- numElements = std::max (numElements,
97
- unsigned (TypeSubElementCount (elt, mod, context)));
92
+ numElements += unsigned (TypeSubElementCount (elt, mod, context));
98
93
}
99
94
number = numElements + 1 ;
95
+ if (type.isValueTypeWithDeinit ()) {
96
+ // 'self' has its own liveness represented as an additional field at the
97
+ // end of the structure.
98
+ ++number;
99
+ }
100
100
return ;
101
101
}
102
102
@@ -190,19 +190,20 @@ SubElementOffset::computeForAddress(SILValue projectionDerivedFromRoot,
190
190
continue ;
191
191
}
192
192
193
- // In the case of enums, we note that our representation is:
194
- //
195
- // ---------|Enum| ---
196
- // / \
197
- // / \
198
- // v v
199
- // |Bits for Max Sized Payload| |Discrim Bit|
200
- //
201
- // So our payload is always going to start at the current field number since
202
- // we are the left most child of our parent enum. So we just need to look
203
- // through to our parent enum.
204
193
if (auto *enumData = dyn_cast<UncheckedTakeEnumDataAddrInst>(
205
194
projectionDerivedFromRoot)) {
195
+ auto ty = enumData->getOperand ()->getType ();
196
+ auto *enumDecl = enumData->getEnumDecl ();
197
+ for (auto *element : enumDecl->getAllElements ()) {
198
+ if (!element->hasAssociatedValues ())
199
+ continue ;
200
+ if (element == enumData->getElement ())
201
+ break ;
202
+ auto context = TypeExpansionContext (*rootAddress->getFunction ());
203
+ auto elementTy = ty.getEnumElementType (element, mod, context);
204
+ finalSubElementOffset +=
205
+ unsigned (TypeSubElementCount (elementTy, mod, context));
206
+ }
206
207
projectionDerivedFromRoot = enumData->getOperand ();
207
208
continue ;
208
209
}
@@ -376,6 +377,7 @@ SubElementOffset::computeForValue(SILValue projectionDerivedFromRoot,
376
377
377
378
void TypeTreeLeafTypeRange::constructFilteredProjections (
378
379
SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
380
+ DominanceInfo *domTree,
379
381
llvm::function_ref<bool (SILValue, TypeTreeLeafTypeRange)> callback) {
380
382
auto *fn = insertPt->getFunction ();
381
383
SILType type = value->getType ();
@@ -419,27 +421,56 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
419
421
return ;
420
422
}
421
423
422
- // We only allow for enums that can be completely destroyed. If there is code
423
- // where an enum should be partially destroyed, we need to treat the
424
- // unchecked_take_enum_data_addr as a separate value whose liveness we are
425
- // tracking.
426
424
if (auto *enumDecl = type.getEnumOrBoundGenericEnum ()) {
425
+ struct ElementRecord {
426
+ EnumElementDecl *element;
427
+ unsigned start;
428
+ unsigned next;
429
+ };
430
+ SmallVector<ElementRecord, 2 > projectedElements;
427
431
unsigned start = startEltOffset;
428
-
429
- unsigned maxSubEltCount = 0 ;
430
432
for (auto *eltDecl : enumDecl->getAllElements ()) {
431
433
if (!eltDecl->hasAssociatedValues ())
432
434
continue ;
435
+
433
436
auto nextType = type.getEnumElementType (eltDecl, fn);
434
- maxSubEltCount =
435
- std::max (maxSubEltCount, unsigned (TypeSubElementCount (nextType, fn)));
437
+ unsigned next = start + TypeSubElementCount (nextType, fn);
438
+ if (noneSet (filterBitVector, start, next)) {
439
+ start = next;
440
+ continue ;
441
+ }
442
+
443
+ projectedElements.push_back ({eltDecl, start, next});
444
+ start = next;
436
445
}
437
446
438
- // Add a bit for the case bit.
439
- unsigned next = maxSubEltCount + 1 ;
447
+ // Add a bit for the discriminator.
448
+ unsigned next = start + 1 ;
449
+
450
+ if (!allSet (filterBitVector, start, next)) {
451
+ for (auto record : projectedElements) {
452
+ // Find a preexisting unchecked_take_enum_data_addr that dominates
453
+ // insertPt.
454
+ bool foundProjection = false ;
455
+ for (auto *user : value->getUsers ()) {
456
+ auto *utedai = dyn_cast<UncheckedTakeEnumDataAddrInst>(user);
457
+ if (!utedai) {
458
+ continue ;
459
+ }
460
+ if (utedai->getElement () != record.element ) {
461
+ continue ;
462
+ }
463
+ if (!domTree->dominates (utedai, insertPt)) {
464
+ continue ;
465
+ }
440
466
441
- // Make sure we are all set.
442
- assert (allSet (filterBitVector, start, next));
467
+ callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ));
468
+ foundProjection = true ;
469
+ }
470
+ // assert(foundProjection);
471
+ }
472
+ return ;
473
+ }
443
474
444
475
// Then just pass back our enum base value as the pointer.
445
476
callback (value, TypeTreeLeafTypeRange (start, next));
@@ -491,17 +522,34 @@ void TypeTreeLeafTypeRange::get(
491
522
// An `inject_enum_addr` only initializes the enum tag.
492
523
if (auto inject = dyn_cast<InjectEnumAddrInst>(op->getUser ())) {
493
524
auto upperBound = *startEltOffset + TypeSubElementCount (projectedValue);
494
- unsigned payloadUpperBound = 0 ;
495
- if (inject->getElement ()->hasAssociatedValues ()) {
496
- auto payloadTy = projectedValue->getType ().getEnumElementType (
497
- inject->getElement (), op->getFunction ());
525
+ // TODO: account for deinit component if enum has deinit.
526
+ assert (!projectedValue->getType ().isValueTypeWithDeinit ());
527
+ ranges.push_back ({upperBound - 1 , upperBound});
528
+ return ;
529
+ }
498
530
499
- payloadUpperBound =
500
- *startEltOffset + TypeSubElementCount (payloadTy, op->getFunction ());
531
+ if (auto *utedai = dyn_cast<UncheckedTakeEnumDataAddrInst>(op->getUser ())) {
532
+ auto *selected = utedai->getElement ();
533
+ auto *enumDecl = utedai->getEnumDecl ();
534
+ unsigned numAtoms = 0 ;
535
+ for (auto *element : enumDecl->getAllElements ()) {
536
+ if (!element->hasAssociatedValues ()) {
537
+ continue ;
538
+ }
539
+ auto elementTy = projectedValue->getType ().getEnumElementType (
540
+ element, op->getFunction ());
541
+ auto elementAtoms =
542
+ unsigned (TypeSubElementCount (elementTy, op->getFunction ()));
543
+ if (element != selected) {
544
+ ranges.push_back ({*startEltOffset + numAtoms,
545
+ *startEltOffset + numAtoms + elementAtoms});
546
+ }
547
+ numAtoms += elementAtoms;
501
548
}
502
549
// TODO: account for deinit component if enum has deinit.
503
550
assert (!projectedValue->getType ().isValueTypeWithDeinit ());
504
- ranges.push_back ({payloadUpperBound, upperBound});
551
+ ranges.push_back (
552
+ {*startEltOffset + numAtoms, *startEltOffset + numAtoms + 1 });
505
553
return ;
506
554
}
507
555
@@ -521,7 +569,7 @@ void TypeTreeLeafTypeRange::get(
521
569
}
522
570
523
571
void TypeTreeLeafTypeRange::constructProjectionsForNeededElements (
524
- SILValue rootValue, SILInstruction *insertPt,
572
+ SILValue rootValue, SILInstruction *insertPt, DominanceInfo *domTree,
525
573
SmallBitVector &neededElements,
526
574
SmallVectorImpl<std::pair<SILValue, TypeTreeLeafTypeRange>>
527
575
&resultingProjections) {
@@ -569,7 +617,7 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
569
617
// recursively process those ranges looking for subranges that have
570
618
// completely set bits.
571
619
range.constructFilteredProjections (
572
- value, insertPt, neededElements,
620
+ value, insertPt, neededElements, domTree,
573
621
[&](SILValue subType, TypeTreeLeafTypeRange range) -> bool {
574
622
worklist.push_back ({subType, range});
575
623
return true ;
0 commit comments