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