@@ -293,6 +293,19 @@ class StackAllocationPromoter {
293293 // / Replace the dummy nodes with new block arguments.
294294 void addBlockArguments (BlockSetVector &phiBlocks);
295295
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+
296309 // / Fix all of the branch instructions and the uses to use
297310 // / the AllocStack definitions (which include stores and Phis).
298311 void fixBranchesAndUses (BlockSetVector &blocks);
@@ -527,6 +540,52 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
527540 deleter.forceDelete (ti);
528541}
529542
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+
530589void StackAllocationPromoter::fixBranchesAndUses (BlockSetVector &phiBlocks) {
531590 // First update uses of the value.
532591 SmallVector<LoadInst *, 4 > collectedLoads;
@@ -582,7 +641,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
582641
583642 // Now that all of the uses are fixed we can fix the branches that point
584643 // to the blocks with the added arguments.
585-
586644 // For each Block with a new Phi argument:
587645 for (auto *block : phiBlocks) {
588646 // Fix all predecessors.
@@ -596,14 +654,30 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
596654 }
597655 }
598656
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+ }
607681 }
608682 }
609683}
0 commit comments