@@ -83,20 +83,20 @@ TypeSubElementCount::TypeSubElementCount(SILType type, SILModule &mod,
8383 return ;
8484 }
8585
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.
9086 if (auto *enumDecl = type.getEnumOrBoundGenericEnum ()) {
9187 unsigned numElements = 0 ;
9288 for (auto *eltDecl : enumDecl->getAllElements ()) {
9389 if (!eltDecl->hasAssociatedValues ())
9490 continue ;
9591 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));
9893 }
9994 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+ }
100100 return ;
101101 }
102102
@@ -190,19 +190,20 @@ SubElementOffset::computeForAddress(SILValue projectionDerivedFromRoot,
190190 continue ;
191191 }
192192
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.
204193 if (auto *enumData = dyn_cast<UncheckedTakeEnumDataAddrInst>(
205194 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+ }
206207 projectionDerivedFromRoot = enumData->getOperand ();
207208 continue ;
208209 }
@@ -376,7 +377,9 @@ SubElementOffset::computeForValue(SILValue projectionDerivedFromRoot,
376377
377378void TypeTreeLeafTypeRange::constructFilteredProjections (
378379 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) {
380383 auto *fn = insertPt->getFunction ();
381384 SILType type = value->getType ();
382385
@@ -408,7 +411,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
408411
409412 auto newValue =
410413 builder.createStructElementAddr (insertPt->getLoc (), value, varDecl);
411- callback (newValue, TypeTreeLeafTypeRange (start, next));
414+ callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy );
412415 start = next;
413416 }
414417 if (type.isValueTypeWithDeinit ()) {
@@ -419,30 +422,63 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
419422 return ;
420423 }
421424
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.
426425 if (auto *enumDecl = type.getEnumOrBoundGenericEnum ()) {
426+ struct ElementRecord {
427+ EnumElementDecl *element;
428+ unsigned start;
429+ unsigned next;
430+ };
431+ SmallVector<ElementRecord, 2 > projectedElements;
427432 unsigned start = startEltOffset;
428-
429- unsigned maxSubEltCount = 0 ;
430433 for (auto *eltDecl : enumDecl->getAllElements ()) {
431434 if (!eltDecl->hasAssociatedValues ())
432435 continue ;
436+
433437 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;
436446 }
437447
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+ }
440467
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+ }
443479
444480 // Then just pass back our enum base value as the pointer.
445- callback (value, TypeTreeLeafTypeRange (start, next));
481+ callback (value, TypeTreeLeafTypeRange (start, next), NeedsDestroy );
446482
447483 // Then set start to next and assert we covered the entire end elt offset.
448484 start = next;
@@ -463,7 +499,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
463499
464500 auto newValue =
465501 builder.createTupleElementAddr (insertPt->getLoc (), value, index);
466- callback (newValue, TypeTreeLeafTypeRange (start, next));
502+ callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy );
467503 start = next;
468504 }
469505 assert (start == endEltOffset);
@@ -491,17 +527,34 @@ void TypeTreeLeafTypeRange::get(
491527 // An `inject_enum_addr` only initializes the enum tag.
492528 if (auto inject = dyn_cast<InjectEnumAddrInst>(op->getUser ())) {
493529 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+ }
498535
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;
501553 }
502554 // TODO: account for deinit component if enum has deinit.
503555 assert (!projectedValue->getType ().isValueTypeWithDeinit ());
504- ranges.push_back ({payloadUpperBound, upperBound});
556+ ranges.push_back (
557+ {*startEltOffset + numAtoms, *startEltOffset + numAtoms + 1 });
505558 return ;
506559 }
507560
@@ -521,17 +574,17 @@ void TypeTreeLeafTypeRange::get(
521574}
522575
523576void TypeTreeLeafTypeRange::constructProjectionsForNeededElements (
524- SILValue rootValue, SILInstruction *insertPt,
577+ SILValue rootValue, SILInstruction *insertPt, DominanceInfo *domTree,
525578 SmallBitVector &neededElements,
526- SmallVectorImpl<std::pair <SILValue, TypeTreeLeafTypeRange>>
579+ SmallVectorImpl<std::tuple <SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t >>
527580 &resultingProjections) {
528581 TypeTreeLeafTypeRange rootRange (rootValue);
529582 (void )rootRange;
530583 assert (rootRange.size () == neededElements.size ());
531584
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 });
535588
536589 // Temporary vector we use for our computation.
537590 SmallBitVector tmp (neededElements.size ());
@@ -543,8 +596,10 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
543596
544597 while (!worklist.empty ()) {
545598 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;
548603
549604 tmp.reset ();
550605 tmp.set (range.startEltOffset , range.endEltOffset );
@@ -561,17 +616,18 @@ void TypeTreeLeafTypeRange::constructProjectionsForNeededElements(
561616 // everything set in the range. In that case, we just add this range to the
562617 // result and continue.
563618 if (allInRange (tmp, range)) {
564- resultingProjections.emplace_back (value, range);
619+ resultingProjections.emplace_back (value, range, needsDestroy );
565620 continue ;
566621 }
567622
568623 // Otherwise, we have a partial range. We need to split our range and then
569624 // recursively process those ranges looking for subranges that have
570625 // completely set bits.
571626 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});
575631 return true ;
576632 });
577633 }
0 commit comments