@@ -228,7 +228,7 @@ namespace {
228228
229229// / Promotes a single AllocStackInst into registers..
230230class StackAllocationPromoter {
231- using BlockSet = BasicBlockSetVector;
231+ using BlockSetVector = BasicBlockSetVector;
232232 using BlockToInstMap = llvm::DenseMap<SILBasicBlock *, SILInstruction *>;
233233
234234 // Use a priority queue keyed on dominator tree level so that inserted nodes
@@ -291,26 +291,40 @@ class StackAllocationPromoter {
291291 void promoteAllocationToPhi ();
292292
293293 // / Replace the dummy nodes with new block arguments.
294- void addBlockArguments (BlockSet &phiBlocks);
294+ void addBlockArguments (BlockSetVector &phiBlocks);
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);
295308
296309 // / Fix all of the branch instructions and the uses to use
297310 // / the AllocStack definitions (which include stores and Phis).
298- void fixBranchesAndUses (BlockSet &blocks);
311+ void fixBranchesAndUses (BlockSetVector &blocks);
299312
300313 // / update the branch instructions with the new Phi argument.
301314 // / The blocks in \p PhiBlocks are blocks that define a value, \p Dest is
302315 // / the branch destination, and \p Pred is the predecessors who's branch we
303316 // / modify.
304- void fixPhiPredBlock (BlockSet &phiBlocks, SILBasicBlock *dest,
317+ void fixPhiPredBlock (BlockSetVector &phiBlocks, SILBasicBlock *dest,
305318 SILBasicBlock *pred);
306319
307320 // / Get the value for this AllocStack variable that is
308321 // / flowing out of StartBB.
309- SILValue getLiveOutValue (BlockSet &phiBlocks, SILBasicBlock *startBlock);
322+ SILValue getLiveOutValue (BlockSetVector &phiBlocks,
323+ SILBasicBlock *startBlock);
310324
311325 // / Get the value for this AllocStack variable that is
312326 // / flowing into BB.
313- SILValue getLiveInValue (BlockSet &phiBlocks, SILBasicBlock *block);
327+ SILValue getLiveInValue (BlockSetVector &phiBlocks, SILBasicBlock *block);
314328
315329 // / Prune AllocStacks usage in the function. Scan the function
316330 // / and remove in-block usage of the AllocStack. Leave only the first
@@ -450,14 +464,14 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
450464 return lastStore;
451465}
452466
453- void StackAllocationPromoter::addBlockArguments (BlockSet &phiBlocks) {
467+ void StackAllocationPromoter::addBlockArguments (BlockSetVector &phiBlocks) {
454468 LLVM_DEBUG (llvm::dbgs () << " *** Adding new block arguments.\n " );
455469
456470 for (auto *block : phiBlocks)
457471 block->createPhiArgument (asi->getElementType (), OwnershipKind::Owned);
458472}
459473
460- SILValue StackAllocationPromoter::getLiveOutValue (BlockSet &phiBlocks,
474+ SILValue StackAllocationPromoter::getLiveOutValue (BlockSetVector &phiBlocks,
461475 SILBasicBlock *startBlock) {
462476 LLVM_DEBUG (llvm::dbgs () << " *** Searching for a value definition.\n " );
463477 // Walk the Dom tree in search of a defining value:
@@ -489,7 +503,7 @@ SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
489503 return SILUndef::get (asi->getElementType (), *asi->getFunction ());
490504}
491505
492- SILValue StackAllocationPromoter::getLiveInValue (BlockSet &phiBlocks,
506+ SILValue StackAllocationPromoter::getLiveInValue (BlockSetVector &phiBlocks,
493507 SILBasicBlock *block) {
494508 // First, check if there is a Phi value in the current block. We know that
495509 // our loads happen before stores, so we need to first check for Phi nodes
@@ -512,7 +526,7 @@ SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
512526 return getLiveOutValue (phiBlocks, iDom->getBlock ());
513527}
514528
515- void StackAllocationPromoter::fixPhiPredBlock (BlockSet &phiBlocks,
529+ void StackAllocationPromoter::fixPhiPredBlock (BlockSetVector &phiBlocks,
516530 SILBasicBlock *destBlock,
517531 SILBasicBlock *predBlock) {
518532 TermInst *ti = predBlock->getTerminator ();
@@ -526,7 +540,53 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
526540 deleter.forceDelete (ti);
527541}
528542
529- void StackAllocationPromoter::fixBranchesAndUses (BlockSet &phiBlocks) {
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+
589+ void StackAllocationPromoter::fixBranchesAndUses (BlockSetVector &phiBlocks) {
530590 // First update uses of the value.
531591 SmallVector<LoadInst *, 4 > collectedLoads;
532592
@@ -581,7 +641,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
581641
582642 // Now that all of the uses are fixed we can fix the branches that point
583643 // to the blocks with the added arguments.
584-
585644 // For each Block with a new Phi argument:
586645 for (auto *block : phiBlocks) {
587646 // Fix all predecessors.
@@ -595,21 +654,37 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
595654 }
596655 }
597656
598- // If the owned phi arg we added did not have any uses, create end_lifetime to
599- // end its lifetime. In asserts mode, make sure we have only undef incoming
600- // values for such phi args.
601- for (auto *block : phiBlocks) {
602- auto *phiArg =
603- cast<SILPhiArgument>(block->getArgument (block->getNumArguments () - 1 ));
604- if (phiArg->use_empty ()) {
605- 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+ }
606681 }
607682 }
608683}
609684
610685void StackAllocationPromoter::pruneAllocStackUsage () {
611686 LLVM_DEBUG (llvm::dbgs () << " *** Pruning : " << *asi);
612- BlockSet functionBlocks (asi->getFunction ());
687+ BlockSetVector functionBlocks (asi->getFunction ());
613688
614689 // Insert all of the blocks that asi is live in.
615690 for (auto *use : asi->getUses ())
@@ -630,7 +705,7 @@ void StackAllocationPromoter::promoteAllocationToPhi() {
630705 LLVM_DEBUG (llvm::dbgs () << " *** Placing Phis for : " << *asi);
631706
632707 // A list of blocks that will require new Phi values.
633- BlockSet phiBlocks (asi->getFunction ());
708+ BlockSetVector phiBlocks (asi->getFunction ());
634709
635710 // The "piggy-bank" data-structure that we use for processing the dom-tree
636711 // bottom-up.
@@ -1048,6 +1123,12 @@ bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc) {
10481123 LLVM_DEBUG (llvm::dbgs () << " *** Memory to register looking at: " << *alloc);
10491124 ++NumAllocStackFound;
10501125
1126+ // In OSSA, don't do Mem2Reg on non-trivial alloc_stack with dynamic_lifetime.
1127+ if (alloc->hasDynamicLifetime () && f.hasOwnership () &&
1128+ !alloc->getType ().isTrivial (f)) {
1129+ return false ;
1130+ }
1131+
10511132 // Don't handle captured AllocStacks.
10521133 bool inSingleBlock = false ;
10531134 if (isCaptured (alloc, inSingleBlock)) {
0 commit comments