@@ -375,6 +375,39 @@ SubElementOffset::computeForValue(SILValue projectionDerivedFromRoot,
375
375
// MARK: TypeTreeLeafTypeRange
376
376
// ===----------------------------------------------------------------------===//
377
377
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
+
378
411
void TypeTreeLeafTypeRange::constructFilteredProjections (
379
412
SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
380
413
DominanceInfo *domTree,
@@ -429,60 +462,72 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
429
462
unsigned next;
430
463
};
431
464
SmallVector<ElementRecord, 2 > projectedElements;
432
- unsigned start = startEltOffset;
465
+ unsigned runningStart = startEltOffset;
433
466
for (auto *eltDecl : enumDecl->getAllElements ()) {
434
467
if (!eltDecl->hasAssociatedValues ())
435
468
continue ;
436
469
437
- auto nextType = type.getEnumElementType (eltDecl, fn);
438
- unsigned next = start + TypeSubElementCount (nextType , fn);
439
- if (noneSet (filterBitVector, start , next)) {
440
- start = next;
470
+ auto eltTy = type.getEnumElementType (eltDecl, fn);
471
+ unsigned next = runningStart + TypeSubElementCount (eltTy , fn);
472
+ if (noneSet (filterBitVector, runningStart , next)) {
473
+ runningStart = next;
441
474
continue ;
442
475
}
443
476
444
- projectedElements.push_back ({eltDecl, start , next});
445
- start = next;
477
+ projectedElements.push_back ({eltDecl, runningStart , next});
478
+ runningStart = next;
446
479
}
480
+ assert ((runningStart + 1 + (type.isValueTypeWithDeinit () ? 1 : 0 )) ==
481
+ endEltOffset);
447
482
448
- // Add a bit for the discriminator.
449
- unsigned next = start + 1 ;
450
-
451
- if (!allSet (filterBitVector, start, next)) {
483
+ if (!allSet (filterBitVector, startEltOffset, endEltOffset)) {
484
+ TinyPtrVector<SwitchEnumAddrInst *> seais;
452
485
for (auto record : projectedElements) {
453
486
// Find a preexisting unchecked_take_enum_data_addr that dominates
454
487
// insertPt.
455
488
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 ;
489
+ StackList<SILValue> worklist (value->getFunction ());
490
+ worklist.push_back (value);
491
+ while (!worklist.empty ()) {
492
+ auto v = worklist.pop_back_val ();
493
+ for (auto *user : v->getUsers ()) {
494
+ if (auto *ddi = dyn_cast<DropDeinitInst>(user)) {
495
+ worklist.push_back (ddi);
496
+ continue ;
497
+ }
498
+ if (auto *seai = dyn_cast<SwitchEnumAddrInst>(user)) {
499
+ seais.push_back (seai);
500
+ }
501
+ auto *utedai = dyn_cast<UncheckedTakeEnumDataAddrInst>(user);
502
+ if (!utedai) {
503
+ continue ;
504
+ }
505
+ if (utedai->getElement () != record.element ) {
506
+ continue ;
507
+ }
508
+ if (!domTree->dominates (utedai, insertPt)) {
509
+ continue ;
510
+ }
511
+
512
+ callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ),
513
+ NeedsDestroy);
514
+ foundProjection = true ;
463
515
}
464
- if (!domTree->dominates (utedai, insertPt)) {
465
- continue ;
466
- }
467
-
468
- callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ),
469
- DoesNotNeedDestroy);
470
- foundProjection = true ;
471
516
}
517
+ (void )foundProjection;
472
518
assert (foundProjection ||
473
- llvm::count_if (enumDecl->getAllElements (), [](auto *elt) {
474
- return elt->hasAssociatedValues ();
475
- }) == 1 );
519
+ llvm::count_if (
520
+ enumDecl->getAllElements (),
521
+ [](auto *elt) { return elt->hasAssociatedValues (); }) == 1 ||
522
+ isDominatedByPayloadlessSwitchEnumAddrDests (insertPt, seais,
523
+ domTree));
476
524
}
477
525
return ;
478
526
}
479
527
480
528
// 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);
529
+ callback (value, TypeTreeLeafTypeRange (startEltOffset, endEltOffset),
530
+ NeedsDestroy);
486
531
return ;
487
532
}
488
533
@@ -526,9 +571,12 @@ void TypeTreeLeafTypeRange::get(
526
571
527
572
// An `inject_enum_addr` only initializes the enum tag.
528
573
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 ());
574
+ // Subtract the deinit bit, if any: the discriminator bit is before it:
575
+ //
576
+ // [ case1 bits ..., case2 bits, ..., discriminator bit, deinit bit ]
577
+ auto deinitBits = projectedValue->getType ().isValueTypeWithDeinit () ? 1 : 0 ;
578
+ auto upperBound =
579
+ *startEltOffset + TypeSubElementCount (projectedValue) - deinitBits;
532
580
ranges.push_back ({upperBound - 1 , upperBound});
533
581
return ;
534
582
}
@@ -551,10 +599,11 @@ void TypeTreeLeafTypeRange::get(
551
599
}
552
600
numAtoms += elementAtoms;
553
601
}
554
- // TODO: account for deinit component if enum has deinit.
555
- assert (!projectedValue->getType ().isValueTypeWithDeinit ());
602
+ // The discriminator bit is consumed.
556
603
ranges.push_back (
557
604
{*startEltOffset + numAtoms, *startEltOffset + numAtoms + 1 });
605
+ // The deinit bit is _not_ consumed. A drop_deinit is required to
606
+ // consumingly switch an enum with a deinit.
558
607
return ;
559
608
}
560
609
0 commit comments