@@ -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,7 +377,9 @@ SubElementOffset::computeForValue(SILValue projectionDerivedFromRoot,
376
377
377
378
void TypeTreeLeafTypeRange::constructFilteredProjections (
378
379
SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
379
- llvm::function_ref<bool (SILValue, TypeTreeLeafTypeRange)> callback) {
380
+ DominanceInfo *domTree,
381
+ llvm::function_ref<bool (SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t)>
382
+ callback) {
380
383
auto *fn = insertPt->getFunction ();
381
384
SILType type = value->getType ();
382
385
@@ -408,7 +411,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
408
411
409
412
auto newValue =
410
413
builder.createStructElementAddr (insertPt->getLoc (), value, varDecl);
411
- callback (newValue, TypeTreeLeafTypeRange (start, next));
414
+ callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy );
412
415
start = next;
413
416
}
414
417
if (type.isValueTypeWithDeinit ()) {
@@ -419,30 +422,63 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
419
422
return ;
420
423
}
421
424
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
425
if (auto *enumDecl = type.getEnumOrBoundGenericEnum ()) {
426
+ struct ElementRecord {
427
+ EnumElementDecl *element;
428
+ unsigned start;
429
+ unsigned next;
430
+ };
431
+ SmallVector<ElementRecord, 2 > projectedElements;
427
432
unsigned start = startEltOffset;
428
-
429
- unsigned maxSubEltCount = 0 ;
430
433
for (auto *eltDecl : enumDecl->getAllElements ()) {
431
434
if (!eltDecl->hasAssociatedValues ())
432
435
continue ;
436
+
433
437
auto nextType = type.getEnumElementType (eltDecl, fn);
434
- maxSubEltCount =
435
- std::max (maxSubEltCount, unsigned (TypeSubElementCount (nextType, fn)));
438
+ unsigned next = start + TypeSubElementCount (nextType, fn);
439
+ if (noneSet (filterBitVector, start, next)) {
440
+ start = next;
441
+ continue ;
442
+ }
443
+
444
+ projectedElements.push_back ({eltDecl, start, next});
445
+ start = next;
436
446
}
437
447
438
- // Add a bit for the case bit.
439
- unsigned next = maxSubEltCount + 1 ;
448
+ // Add a bit for the discriminator.
449
+ unsigned next = start + 1 ;
450
+
451
+ if (!allSet (filterBitVector, start, next)) {
452
+ for (auto record : projectedElements) {
453
+ // Find a preexisting unchecked_take_enum_data_addr that dominates
454
+ // insertPt.
455
+ bool foundProjection = false ;
456
+ for (auto *user : value->getUsers ()) {
457
+ auto *utedai = dyn_cast<UncheckedTakeEnumDataAddrInst>(user);
458
+ if (!utedai) {
459
+ continue ;
460
+ }
461
+ if (utedai->getElement () == record.element ) {
462
+ continue ;
463
+ }
464
+ if (!domTree->dominates (utedai, insertPt)) {
465
+ continue ;
466
+ }
440
467
441
- // Make sure we are all set.
442
- assert (allSet (filterBitVector, start, next));
468
+ callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ),
469
+ DoesNotNeedDestroy);
470
+ foundProjection = true ;
471
+ }
472
+ assert (foundProjection ||
473
+ llvm::count_if (enumDecl->getAllElements (), [](auto *elt) {
474
+ return elt->hasAssociatedValues ();
475
+ }) == 1 );
476
+ }
477
+ return ;
478
+ }
443
479
444
480
// Then just pass back our enum base value as the pointer.
445
- callback (value, TypeTreeLeafTypeRange (start, next));
481
+ callback (value, TypeTreeLeafTypeRange (start, next), NeedsDestroy );
446
482
447
483
// Then set start to next and assert we covered the entire end elt offset.
448
484
start = next;
@@ -463,7 +499,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
463
499
464
500
auto newValue =
465
501
builder.createTupleElementAddr (insertPt->getLoc (), value, index );
466
- callback (newValue, TypeTreeLeafTypeRange (start, next));
502
+ callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy );
467
503
start = next;
468
504
}
469
505
assert (start == endEltOffset);
@@ -491,17 +527,34 @@ void TypeTreeLeafTypeRange::get(
491
527
// An `inject_enum_addr` only initializes the enum tag.
492
528
if (auto inject = dyn_cast<InjectEnumAddrInst>(op->getUser ())) {
493
529
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 ());
530
+ // TODO: account for deinit component if enum has deinit.
531
+ assert (!projectedValue->getType ().isValueTypeWithDeinit ());
532
+ ranges.push_back ({upperBound - 1 , upperBound});
533
+ return ;
534
+ }
498
535
499
- payloadUpperBound =
500
- *startEltOffset + TypeSubElementCount (payloadTy, op->getFunction ());
536
+ if (auto *utedai = dyn_cast<UncheckedTakeEnumDataAddrInst>(op->getUser ())) {
537
+ auto *selected = utedai->getElement ();
538
+ auto *enumDecl = utedai->getEnumDecl ();
539
+ unsigned numAtoms = 0 ;
540
+ for (auto *element : enumDecl->getAllElements ()) {
541
+ if (!element->hasAssociatedValues ()) {
542
+ continue ;
543
+ }
544
+ auto elementTy = projectedValue->getType ().getEnumElementType (
545
+ element, op->getFunction ());
546
+ auto elementAtoms =
547
+ unsigned (TypeSubElementCount (elementTy, op->getFunction ()));
548
+ if (element != selected) {
549
+ ranges.push_back ({*startEltOffset + numAtoms,
550
+ *startEltOffset + numAtoms + elementAtoms});
551
+ }
552
+ numAtoms += elementAtoms;
501
553
}
502
554
// TODO: account for deinit component if enum has deinit.
503
555
assert (!projectedValue->getType ().isValueTypeWithDeinit ());
504
- ranges.push_back ({payloadUpperBound, upperBound});
556
+ ranges.push_back (
557
+ {*startEltOffset + numAtoms, *startEltOffset + numAtoms + 1 });
505
558
return ;
506
559
}
507
560
@@ -521,17 +574,17 @@ void TypeTreeLeafTypeRange::get(
521
574
}
522
575
523
576
void TypeTreeLeafTypeRange::constructProjectionsForNeededElements (
524
- SILValue rootValue, SILInstruction *insertPt,
577
+ SILValue rootValue, SILInstruction *insertPt, DominanceInfo *domTree,
525
578
SmallBitVector &neededElements,
526
- SmallVectorImpl<std::pair <SILValue, TypeTreeLeafTypeRange>>
579
+ SmallVectorImpl<std::tuple <SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t >>
527
580
&resultingProjections) {
528
581
TypeTreeLeafTypeRange rootRange (rootValue);
529
582
(void )rootRange;
530
583
assert (rootRange.size () == neededElements.size ());
531
584
532
- StackList<std::pair <SILValue, TypeTreeLeafTypeRange>> worklist (
533
- insertPt->getFunction ());
534
- worklist.push_back ({rootValue, rootRange});
585
+ StackList<std::tuple <SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t>>
586
+ worklist ( insertPt->getFunction ());
587
+ worklist.push_back ({rootValue, rootRange, NeedsDestroy });
535
588
536
589
// Temporary vector we use for our computation.
537
590
SmallBitVector tmp (neededElements.size ());
@@ -543,8 +596,10 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
543
596
544
597
while (!worklist.empty ()) {
545
598
auto pair = worklist.pop_back_val ();
546
- auto value = pair.first ;
547
- auto range = pair.second ;
599
+ SILValue value;
600
+ TypeTreeLeafTypeRange range;
601
+ NeedsDestroy_t needsDestroy;
602
+ std::tie (value, range, needsDestroy) = pair;
548
603
549
604
tmp.reset ();
550
605
tmp.set (range.startEltOffset , range.endEltOffset );
@@ -561,17 +616,18 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
561
616
// everything set in the range. In that case, we just add this range to the
562
617
// result and continue.
563
618
if (allInRange (tmp, range)) {
564
- resultingProjections.emplace_back (value, range);
619
+ resultingProjections.emplace_back (value, range, needsDestroy );
565
620
continue ;
566
621
}
567
622
568
623
// Otherwise, we have a partial range. We need to split our range and then
569
624
// recursively process those ranges looking for subranges that have
570
625
// completely set bits.
571
626
range.constructFilteredProjections (
572
- value, insertPt, neededElements,
573
- [&](SILValue subType, TypeTreeLeafTypeRange range) -> bool {
574
- worklist.push_back ({subType, range});
627
+ value, insertPt, neededElements, domTree,
628
+ [&](SILValue subType, TypeTreeLeafTypeRange range,
629
+ NeedsDestroy_t needsDestroy) -> bool {
630
+ worklist.push_back ({subType, range, needsDestroy});
575
631
return true ;
576
632
});
577
633
}
0 commit comments