@@ -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);
@@ -473,33 +509,53 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
473
509
llvm_unreachable (" Not understand subtype" );
474
510
}
475
511
476
- std::optional<TypeTreeLeafTypeRange>
477
- TypeTreeLeafTypeRange::get (Operand *op, SILValue rootValue) {
512
+ void TypeTreeLeafTypeRange::get (
513
+ Operand *op, SILValue rootValue,
514
+ SmallVectorImpl<TypeTreeLeafTypeRange> &ranges) {
478
515
auto projectedValue = op->get ();
479
516
auto startEltOffset = SubElementOffset::compute (projectedValue, rootValue);
480
517
if (!startEltOffset)
481
- return std::nullopt ;
518
+ return ;
482
519
483
520
// A drop_deinit only consumes the deinit bit of its operand.
484
521
if (isa<DropDeinitInst>(op->getUser ())) {
485
522
auto upperBound = *startEltOffset + TypeSubElementCount (projectedValue);
486
- return {{upperBound - 1 , upperBound}};
523
+ ranges.push_back ({upperBound - 1 , upperBound});
524
+ return ;
487
525
}
488
526
489
527
// An `inject_enum_addr` only initializes the enum tag.
490
528
if (auto inject = dyn_cast<InjectEnumAddrInst>(op->getUser ())) {
491
529
auto upperBound = *startEltOffset + TypeSubElementCount (projectedValue);
492
- unsigned payloadUpperBound = 0 ;
493
- if (inject->getElement ()->hasAssociatedValues ()) {
494
- auto payloadTy = projectedValue->getType ().getEnumElementType (
495
- 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
+ }
496
535
497
- payloadUpperBound =
498
- *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;
499
553
}
500
554
// TODO: account for deinit component if enum has deinit.
501
555
assert (!projectedValue->getType ().isValueTypeWithDeinit ());
502
- return {{payloadUpperBound, upperBound}};
556
+ ranges.push_back (
557
+ {*startEltOffset + numAtoms, *startEltOffset + numAtoms + 1 });
558
+ return ;
503
559
}
504
560
505
561
// Uses that borrow a value do not involve the deinit bit.
@@ -512,23 +568,23 @@ TypeTreeLeafTypeRange::get(Operand *op, SILValue rootValue) {
512
568
deinitBitOffset = 1 ;
513
569
}
514
570
515
- return { {*startEltOffset, *startEltOffset +
516
- TypeSubElementCount (projectedValue) -
517
- deinitBitOffset}} ;
571
+ ranges. push_back ( {*startEltOffset, *startEltOffset +
572
+ TypeSubElementCount (projectedValue) -
573
+ deinitBitOffset}) ;
518
574
}
519
575
520
576
void TypeTreeLeafTypeRange::constructProjectionsForNeededElements (
521
- SILValue rootValue, SILInstruction *insertPt,
577
+ SILValue rootValue, SILInstruction *insertPt, DominanceInfo *domTree,
522
578
SmallBitVector &neededElements,
523
- SmallVectorImpl<std::pair <SILValue, TypeTreeLeafTypeRange>>
579
+ SmallVectorImpl<std::tuple <SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t >>
524
580
&resultingProjections) {
525
581
TypeTreeLeafTypeRange rootRange (rootValue);
526
582
(void )rootRange;
527
583
assert (rootRange.size () == neededElements.size ());
528
584
529
- StackList<std::pair <SILValue, TypeTreeLeafTypeRange>> worklist (
530
- insertPt->getFunction ());
531
- worklist.push_back ({rootValue, rootRange});
585
+ StackList<std::tuple <SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t>>
586
+ worklist ( insertPt->getFunction ());
587
+ worklist.push_back ({rootValue, rootRange, NeedsDestroy });
532
588
533
589
// Temporary vector we use for our computation.
534
590
SmallBitVector tmp (neededElements.size ());
@@ -540,8 +596,10 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
540
596
541
597
while (!worklist.empty ()) {
542
598
auto pair = worklist.pop_back_val ();
543
- auto value = pair.first ;
544
- auto range = pair.second ;
599
+ SILValue value;
600
+ TypeTreeLeafTypeRange range;
601
+ NeedsDestroy_t needsDestroy;
602
+ std::tie (value, range, needsDestroy) = pair;
545
603
546
604
tmp.reset ();
547
605
tmp.set (range.startEltOffset , range.endEltOffset );
@@ -558,17 +616,18 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
558
616
// everything set in the range. In that case, we just add this range to the
559
617
// result and continue.
560
618
if (allInRange (tmp, range)) {
561
- resultingProjections.emplace_back (value, range);
619
+ resultingProjections.emplace_back (value, range, needsDestroy );
562
620
continue ;
563
621
}
564
622
565
623
// Otherwise, we have a partial range. We need to split our range and then
566
624
// recursively process those ranges looking for subranges that have
567
625
// completely set bits.
568
626
range.constructFilteredProjections (
569
- value, insertPt, neededElements,
570
- [&](SILValue subType, TypeTreeLeafTypeRange range) -> bool {
571
- 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});
572
631
return true ;
573
632
});
574
633
}
0 commit comments