@@ -375,13 +375,50 @@ SubElementOffset::computeForValue(SILValue projectionDerivedFromRoot,
375375// MARK: TypeTreeLeafTypeRange
376376// ===----------------------------------------------------------------------===//
377377
378+ // / Whether \p targetInst is dominated by one of the provided switch_enum_addr's
379+ // / destination blocks whose corresponding enum element has no associated values
380+ // / which need to be destroyed (i.e. either it has no associated values or they
381+ // / are trivial).
382+ static bool isDominatedByPayloadlessSwitchEnumAddrDests (
383+ SILInstruction *targetInst, ArrayRef<SwitchEnumAddrInst *> seais,
384+ DominanceInfo *domTree) {
385+ if (seais.empty ())
386+ return false ;
387+ auto *target = targetInst->getParent ();
388+ for (auto *seai : seais) {
389+ if (!domTree->dominates (seai, targetInst)) {
390+ continue ;
391+ }
392+ auto size = seai->getNumCases ();
393+ auto ty = seai->getOperand ()->getType ();
394+ for (unsigned index = 0 ; index < size; ++index) {
395+ auto pair = seai->getCase (index);
396+ auto *eltDecl = pair.first ;
397+ if (eltDecl->hasAssociatedValues ()) {
398+ auto eltTy = ty.getEnumElementType (eltDecl, seai->getFunction ());
399+ if (!eltTy.isTrivial (*seai->getFunction ())) {
400+ continue ;
401+ }
402+ }
403+ auto *block = pair.second ;
404+ if (domTree->dominates (block, target))
405+ return true ;
406+ }
407+ }
408+ return false ;
409+ }
410+
378411void TypeTreeLeafTypeRange::constructFilteredProjections (
379412 SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
380413 DominanceInfo *domTree,
381414 llvm::function_ref<bool (SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t)>
382415 callback) {
383416 auto *fn = insertPt->getFunction ();
384417 SILType type = value->getType ();
418+ auto loc =
419+ (insertPt->getLoc ().getKind () != SILLocation::ArtificialUnreachableKind)
420+ ? insertPt->getLoc ()
421+ : RegularLocation::getAutoGeneratedLocation ();
385422
386423 PRUNED_LIVENESS_LOG (llvm::dbgs () << " ConstructFilteredProjection. Bv: "
387424 << filterBitVector << ' \n ' );
@@ -409,8 +446,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
409446 continue ;
410447 }
411448
412- auto newValue =
413- builder.createStructElementAddr (insertPt->getLoc (), value, varDecl);
449+ auto newValue = builder.createStructElementAddr (loc, value, varDecl);
414450 callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy);
415451 start = next;
416452 }
@@ -429,60 +465,72 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
429465 unsigned next;
430466 };
431467 SmallVector<ElementRecord, 2 > projectedElements;
432- unsigned start = startEltOffset;
468+ unsigned runningStart = startEltOffset;
433469 for (auto *eltDecl : enumDecl->getAllElements ()) {
434470 if (!eltDecl->hasAssociatedValues ())
435471 continue ;
436472
437- auto nextType = type.getEnumElementType (eltDecl, fn);
438- unsigned next = start + TypeSubElementCount (nextType , fn);
439- if (noneSet (filterBitVector, start , next)) {
440- start = next;
473+ auto eltTy = type.getEnumElementType (eltDecl, fn);
474+ unsigned next = runningStart + TypeSubElementCount (eltTy , fn);
475+ if (noneSet (filterBitVector, runningStart , next)) {
476+ runningStart = next;
441477 continue ;
442478 }
443479
444- projectedElements.push_back ({eltDecl, start , next});
445- start = next;
480+ projectedElements.push_back ({eltDecl, runningStart , next});
481+ runningStart = next;
446482 }
483+ assert ((runningStart + 1 + (type.isValueTypeWithDeinit () ? 1 : 0 )) ==
484+ endEltOffset);
447485
448- // Add a bit for the discriminator.
449- unsigned next = start + 1 ;
450-
451- if (!allSet (filterBitVector, start, next)) {
486+ if (!allSet (filterBitVector, startEltOffset, endEltOffset)) {
487+ TinyPtrVector<SwitchEnumAddrInst *> seais;
452488 for (auto record : projectedElements) {
453489 // Find a preexisting unchecked_take_enum_data_addr that dominates
454490 // insertPt.
455491 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 ;
492+ StackList<SILValue> worklist (value->getFunction ());
493+ worklist.push_back (value);
494+ while (!worklist.empty ()) {
495+ auto v = worklist.pop_back_val ();
496+ for (auto *user : v->getUsers ()) {
497+ if (auto *ddi = dyn_cast<DropDeinitInst>(user)) {
498+ worklist.push_back (ddi);
499+ continue ;
500+ }
501+ if (auto *seai = dyn_cast<SwitchEnumAddrInst>(user)) {
502+ seais.push_back (seai);
503+ }
504+ auto *utedai = dyn_cast<UncheckedTakeEnumDataAddrInst>(user);
505+ if (!utedai) {
506+ continue ;
507+ }
508+ if (utedai->getElement () != record.element ) {
509+ continue ;
510+ }
511+ if (!domTree->dominates (utedai, insertPt)) {
512+ continue ;
513+ }
514+
515+ callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ),
516+ NeedsDestroy);
517+ foundProjection = true ;
463518 }
464- if (!domTree->dominates (utedai, insertPt)) {
465- continue ;
466- }
467-
468- callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ),
469- DoesNotNeedDestroy);
470- foundProjection = true ;
471519 }
520+ (void )foundProjection;
472521 assert (foundProjection ||
473- llvm::count_if (enumDecl->getAllElements (), [](auto *elt) {
474- return elt->hasAssociatedValues ();
475- }) == 1 );
522+ llvm::count_if (
523+ enumDecl->getAllElements (),
524+ [](auto *elt) { return elt->hasAssociatedValues (); }) == 1 ||
525+ isDominatedByPayloadlessSwitchEnumAddrDests (insertPt, seais,
526+ domTree));
476527 }
477528 return ;
478529 }
479530
480531 // Then just pass back our enum base value as the pointer.
481- callback (value, TypeTreeLeafTypeRange (start, next), NeedsDestroy);
482-
483- // Then set start to next and assert we covered the entire end elt offset.
484- start = next;
485- assert (start == endEltOffset);
532+ callback (value, TypeTreeLeafTypeRange (startEltOffset, endEltOffset),
533+ NeedsDestroy);
486534 return ;
487535 }
488536
@@ -497,8 +545,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
497545 continue ;
498546 }
499547
500- auto newValue =
501- builder.createTupleElementAddr (insertPt->getLoc (), value, index);
548+ auto newValue = builder.createTupleElementAddr (loc, value, index);
502549 callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy);
503550 start = next;
504551 }
@@ -526,9 +573,12 @@ void TypeTreeLeafTypeRange::get(
526573
527574 // An `inject_enum_addr` only initializes the enum tag.
528575 if (auto inject = dyn_cast<InjectEnumAddrInst>(op->getUser ())) {
529- auto upperBound = *startEltOffset + TypeSubElementCount (projectedValue);
530- // TODO: account for deinit component if enum has deinit.
531- assert (!projectedValue->getType ().isValueTypeWithDeinit ());
576+ // Subtract the deinit bit, if any: the discriminator bit is before it:
577+ //
578+ // [ case1 bits ..., case2 bits, ..., discriminator bit, deinit bit ]
579+ auto deinitBits = projectedValue->getType ().isValueTypeWithDeinit () ? 1 : 0 ;
580+ auto upperBound =
581+ *startEltOffset + TypeSubElementCount (projectedValue) - deinitBits;
532582 ranges.push_back ({upperBound - 1 , upperBound});
533583 return ;
534584 }
@@ -551,10 +601,11 @@ void TypeTreeLeafTypeRange::get(
551601 }
552602 numAtoms += elementAtoms;
553603 }
554- // TODO: account for deinit component if enum has deinit.
555- assert (!projectedValue->getType ().isValueTypeWithDeinit ());
604+ // The discriminator bit is consumed.
556605 ranges.push_back (
557606 {*startEltOffset + numAtoms, *startEltOffset + numAtoms + 1 });
607+ // The deinit bit is _not_ consumed. A drop_deinit is required to
608+ // consumingly switch an enum with a deinit.
558609 return ;
559610 }
560611
0 commit comments