@@ -293,6 +293,19 @@ class StackAllocationPromoter {
293
293
// / Replace the dummy nodes with new block arguments.
294
294
void addBlockArguments (BlockSetVector &phiBlocks);
295
295
296
+ // / Check if \p phi is a proactively added phi by SILMem2Reg
297
+ bool isProactivePhi (SILPhiArgument *phi, const BlockSetVector &phiBlocks);
298
+
299
+ // / Check if \p proactivePhi is live.
300
+ bool isNecessaryProactivePhi (SILPhiArgument *proactivePhi,
301
+ const BlockSetVector &phiBlocks);
302
+
303
+ // / Given a \p proactivePhi that is live, backward propagate liveness to
304
+ // / other proactivePhis.
305
+ void propagateLiveness (SILPhiArgument *proactivePhi,
306
+ const BlockSetVector &phiBlocks,
307
+ SmallPtrSetImpl<SILPhiArgument *> &livePhis);
308
+
296
309
// / Fix all of the branch instructions and the uses to use
297
310
// / the AllocStack definitions (which include stores and Phis).
298
311
void fixBranchesAndUses (BlockSetVector &blocks);
@@ -527,6 +540,52 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
527
540
deleter.forceDelete (ti);
528
541
}
529
542
543
+ bool StackAllocationPromoter::isProactivePhi (SILPhiArgument *phi,
544
+ const BlockSetVector &phiBlocks) {
545
+ auto *phiBlock = phi->getParentBlock ();
546
+ return phiBlocks.contains (phiBlock) &&
547
+ phi == phiBlock->getArgument (phiBlock->getNumArguments () - 1 );
548
+ }
549
+
550
+ bool StackAllocationPromoter::isNecessaryProactivePhi (
551
+ SILPhiArgument *proactivePhi, const BlockSetVector &phiBlocks) {
552
+ assert (isProactivePhi (proactivePhi, phiBlocks));
553
+ for (auto *use : proactivePhi->getUses ()) {
554
+ auto *branch = dyn_cast<BranchInst>(use->getUser ());
555
+ // A non-branch use is a necessary use
556
+ if (!branch)
557
+ return true ;
558
+ auto *destBB = branch->getDestBB ();
559
+ auto opNum = use->getOperandNumber ();
560
+ // A phi has a necessary use if it is used as a branch op for a
561
+ // non-proactive phi
562
+ if (!phiBlocks.contains (destBB) || (opNum != branch->getNumArgs () - 1 ))
563
+ return true ;
564
+ }
565
+ return false ;
566
+ }
567
+
568
+ void StackAllocationPromoter::propagateLiveness (
569
+ SILPhiArgument *proactivePhi, const BlockSetVector &phiBlocks,
570
+ SmallPtrSetImpl<SILPhiArgument *> &livePhis) {
571
+ assert (isProactivePhi (proactivePhi, phiBlocks));
572
+ if (livePhis.contains (proactivePhi))
573
+ return ;
574
+ // If liveness has not been propagated, go over the incoming operands and mark
575
+ // any operand values that are proactivePhis as live
576
+ livePhis.insert (proactivePhi);
577
+ SmallVector<SILValue> incomingPhiVals;
578
+ proactivePhi->getIncomingPhiValues (incomingPhiVals);
579
+ for (auto &inVal : incomingPhiVals) {
580
+ auto *inPhi = dyn_cast<SILPhiArgument>(inVal);
581
+ if (!inPhi)
582
+ continue ;
583
+ if (!isProactivePhi (inPhi, phiBlocks))
584
+ continue ;
585
+ propagateLiveness (inPhi, phiBlocks, livePhis);
586
+ }
587
+ }
588
+
530
589
void StackAllocationPromoter::fixBranchesAndUses (BlockSetVector &phiBlocks) {
531
590
// First update uses of the value.
532
591
SmallVector<LoadInst *, 4 > collectedLoads;
@@ -582,7 +641,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
582
641
583
642
// Now that all of the uses are fixed we can fix the branches that point
584
643
// to the blocks with the added arguments.
585
-
586
644
// For each Block with a new Phi argument:
587
645
for (auto *block : phiBlocks) {
588
646
// Fix all predecessors.
@@ -596,14 +654,30 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
596
654
}
597
655
}
598
656
599
- // If the owned phi arg we added did not have any uses, create end_lifetime to
600
- // end its lifetime. In asserts mode, make sure we have only undef incoming
601
- // values for such phi args.
602
- for (auto *block : phiBlocks) {
603
- auto *phiArg =
604
- cast<SILPhiArgument>(block->getArgument (block->getNumArguments () - 1 ));
605
- if (phiArg->use_empty ()) {
606
- erasePhiArgument (block, block->getNumArguments () - 1 );
657
+ // Fix ownership of proactively created non-trivial phis
658
+ if (asi->getFunction ()->hasOwnership () &&
659
+ !asi->getType ().isTrivial (*asi->getFunction ())) {
660
+ SmallPtrSet<SILPhiArgument *, 4 > livePhis;
661
+
662
+ for (auto *block : phiBlocks) {
663
+ auto *proactivePhi = cast<SILPhiArgument>(
664
+ block->getArgument (block->getNumArguments () - 1 ));
665
+ // First, check if the proactively added phi is necessary by looking at
666
+ // it's immediate uses.
667
+ if (isNecessaryProactivePhi (proactivePhi, phiBlocks)) {
668
+ // Backward propagate liveness to other dependent proactively added phis
669
+ propagateLiveness (proactivePhi, phiBlocks, livePhis);
670
+ }
671
+ }
672
+ // Go over all proactively added phis, and delete those that were not marked
673
+ // live above.
674
+ for (auto *block : phiBlocks) {
675
+ auto *proactivePhi = cast<SILPhiArgument>(
676
+ block->getArgument (block->getNumArguments () - 1 ));
677
+ if (!livePhis.contains (proactivePhi)) {
678
+ proactivePhi->replaceAllUsesWithUndef ();
679
+ erasePhiArgument (block, block->getNumArguments () - 1 );
680
+ }
607
681
}
608
682
}
609
683
}
0 commit comments