@@ -375,13 +375,50 @@ 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,
381
414
llvm::function_ref<bool (SILValue, TypeTreeLeafTypeRange, NeedsDestroy_t)>
382
415
callback) {
383
416
auto *fn = insertPt->getFunction ();
384
417
SILType type = value->getType ();
418
+ auto loc =
419
+ (insertPt->getLoc ().getKind () != SILLocation::ArtificialUnreachableKind)
420
+ ? insertPt->getLoc ()
421
+ : RegularLocation::getAutoGeneratedLocation ();
385
422
386
423
PRUNED_LIVENESS_LOG (llvm::dbgs () << " ConstructFilteredProjection. Bv: "
387
424
<< filterBitVector << ' \n ' );
@@ -409,8 +446,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
409
446
continue ;
410
447
}
411
448
412
- auto newValue =
413
- builder.createStructElementAddr (insertPt->getLoc (), value, varDecl);
449
+ auto newValue = builder.createStructElementAddr (loc, value, varDecl);
414
450
callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy);
415
451
start = next;
416
452
}
@@ -429,60 +465,72 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
429
465
unsigned next;
430
466
};
431
467
SmallVector<ElementRecord, 2 > projectedElements;
432
- unsigned start = startEltOffset;
468
+ unsigned runningStart = startEltOffset;
433
469
for (auto *eltDecl : enumDecl->getAllElements ()) {
434
470
if (!eltDecl->hasAssociatedValues ())
435
471
continue ;
436
472
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;
441
477
continue ;
442
478
}
443
479
444
- projectedElements.push_back ({eltDecl, start , next});
445
- start = next;
480
+ projectedElements.push_back ({eltDecl, runningStart , next});
481
+ runningStart = next;
446
482
}
483
+ assert ((runningStart + 1 + (type.isValueTypeWithDeinit () ? 1 : 0 )) ==
484
+ endEltOffset);
447
485
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;
452
488
for (auto record : projectedElements) {
453
489
// Find a preexisting unchecked_take_enum_data_addr that dominates
454
490
// insertPt.
455
491
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 ;
463
518
}
464
- if (!domTree->dominates (utedai, insertPt)) {
465
- continue ;
466
- }
467
-
468
- callback (utedai, TypeTreeLeafTypeRange (record.start , record.next ),
469
- DoesNotNeedDestroy);
470
- foundProjection = true ;
471
519
}
520
+ (void )foundProjection;
472
521
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));
476
527
}
477
528
return ;
478
529
}
479
530
480
531
// 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);
486
534
return ;
487
535
}
488
536
@@ -497,8 +545,7 @@ void TypeTreeLeafTypeRange::constructFilteredProjections(
497
545
continue ;
498
546
}
499
547
500
- auto newValue =
501
- builder.createTupleElementAddr (insertPt->getLoc (), value, index);
548
+ auto newValue = builder.createTupleElementAddr (loc, value, index);
502
549
callback (newValue, TypeTreeLeafTypeRange (start, next), NeedsDestroy);
503
550
start = next;
504
551
}
@@ -526,9 +573,12 @@ void TypeTreeLeafTypeRange::get(
526
573
527
574
// An `inject_enum_addr` only initializes the enum tag.
528
575
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;
532
582
ranges.push_back ({upperBound - 1 , upperBound});
533
583
return ;
534
584
}
@@ -551,10 +601,11 @@ void TypeTreeLeafTypeRange::get(
551
601
}
552
602
numAtoms += elementAtoms;
553
603
}
554
- // TODO: account for deinit component if enum has deinit.
555
- assert (!projectedValue->getType ().isValueTypeWithDeinit ());
604
+ // The discriminator bit is consumed.
556
605
ranges.push_back (
557
606
{*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.
558
609
return ;
559
610
}
560
611
0 commit comments