@@ -226,7 +226,7 @@ namespace {
226
226
227
227
// / Promotes a single AllocStackInst into registers..
228
228
class StackAllocationPromoter {
229
- using BlockSet = BasicBlockSetVector;
229
+ using BlockSetVector = BasicBlockSetVector;
230
230
using BlockToInstMap = llvm::DenseMap<SILBasicBlock *, SILInstruction *>;
231
231
232
232
// Use a priority queue keyed on dominator tree level so that inserted nodes
@@ -286,26 +286,40 @@ class StackAllocationPromoter {
286
286
void promoteAllocationToPhi ();
287
287
288
288
// / Replace the dummy nodes with new block arguments.
289
- void addBlockArguments (BlockSet &phiBlocks);
289
+ void addBlockArguments (BlockSetVector &phiBlocks);
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);
290
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
- void fixBranchesAndUses (BlockSet &blocks);
306
+ void fixBranchesAndUses (BlockSetVector &blocks);
294
307
295
308
// / update the branch instructions with the new Phi argument.
296
309
// / The blocks in \p PhiBlocks are blocks that define a value, \p Dest is
297
310
// / the branch destination, and \p Pred is the predecessors who's branch we
298
311
// / modify.
299
- void fixPhiPredBlock (BlockSet &phiBlocks, SILBasicBlock *dest,
312
+ void fixPhiPredBlock (BlockSetVector &phiBlocks, SILBasicBlock *dest,
300
313
SILBasicBlock *pred);
301
314
302
315
// / Get the value for this AllocStack variable that is
303
316
// / flowing out of StartBB.
304
- SILValue getLiveOutValue (BlockSet &phiBlocks, SILBasicBlock *startBlock);
317
+ SILValue getLiveOutValue (BlockSetVector &phiBlocks,
318
+ SILBasicBlock *startBlock);
305
319
306
320
// / Get the value for this AllocStack variable that is
307
321
// / flowing into BB.
308
- SILValue getLiveInValue (BlockSet &phiBlocks, SILBasicBlock *block);
322
+ SILValue getLiveInValue (BlockSetVector &phiBlocks, SILBasicBlock *block);
309
323
310
324
// / Prune AllocStacks usage in the function. Scan the function
311
325
// / and remove in-block usage of the AllocStack. Leave only the first
@@ -445,14 +459,14 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
445
459
return lastStore;
446
460
}
447
461
448
- void StackAllocationPromoter::addBlockArguments (BlockSet &phiBlocks) {
462
+ void StackAllocationPromoter::addBlockArguments (BlockSetVector &phiBlocks) {
449
463
LLVM_DEBUG (llvm::dbgs () << " *** Adding new block arguments.\n " );
450
464
451
465
for (auto *block : phiBlocks)
452
466
block->createPhiArgument (asi->getElementType (), OwnershipKind::Owned);
453
467
}
454
468
455
- SILValue StackAllocationPromoter::getLiveOutValue (BlockSet &phiBlocks,
469
+ SILValue StackAllocationPromoter::getLiveOutValue (BlockSetVector &phiBlocks,
456
470
SILBasicBlock *startBlock) {
457
471
LLVM_DEBUG (llvm::dbgs () << " *** Searching for a value definition.\n " );
458
472
// Walk the Dom tree in search of a defining value:
@@ -484,7 +498,7 @@ SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
484
498
return SILUndef::get (asi->getElementType (), *asi->getFunction ());
485
499
}
486
500
487
- SILValue StackAllocationPromoter::getLiveInValue (BlockSet &phiBlocks,
501
+ SILValue StackAllocationPromoter::getLiveInValue (BlockSetVector &phiBlocks,
488
502
SILBasicBlock *block) {
489
503
// First, check if there is a Phi value in the current block. We know that
490
504
// our loads happen before stores, so we need to first check for Phi nodes
@@ -507,7 +521,7 @@ SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
507
521
return getLiveOutValue (phiBlocks, iDom->getBlock ());
508
522
}
509
523
510
- void StackAllocationPromoter::fixPhiPredBlock (BlockSet &phiBlocks,
524
+ void StackAllocationPromoter::fixPhiPredBlock (BlockSetVector &phiBlocks,
511
525
SILBasicBlock *destBlock,
512
526
SILBasicBlock *predBlock) {
513
527
TermInst *ti = predBlock->getTerminator ();
@@ -521,7 +535,53 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
521
535
ti->eraseFromParent ();
522
536
}
523
537
524
- void StackAllocationPromoter::fixBranchesAndUses (BlockSet &phiBlocks) {
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
+
584
+ void StackAllocationPromoter::fixBranchesAndUses (BlockSetVector &phiBlocks) {
525
585
// First update uses of the value.
526
586
SmallVector<LoadInst *, 4 > collectedLoads;
527
587
@@ -576,7 +636,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
576
636
577
637
// Now that all of the uses are fixed we can fix the branches that point
578
638
// to the blocks with the added arguments.
579
-
580
639
// For each Block with a new Phi argument:
581
640
for (auto *block : phiBlocks) {
582
641
// Fix all predecessors.
@@ -590,21 +649,37 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
590
649
}
591
650
}
592
651
593
- // If the owned phi arg we added did not have any uses, create end_lifetime to
594
- // end its lifetime. In asserts mode, make sure we have only undef incoming
595
- // values for such phi args.
596
- for (auto *block : phiBlocks) {
597
- auto *phiArg =
598
- cast<SILPhiArgument>(block->getArgument (block->getNumArguments () - 1 ));
599
- if (phiArg->use_empty ()) {
600
- 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
+ }
601
676
}
602
677
}
603
678
}
604
679
605
680
void StackAllocationPromoter::pruneAllocStackUsage () {
606
681
LLVM_DEBUG (llvm::dbgs () << " *** Pruning : " << *asi);
607
- BlockSet functionBlocks (asi->getFunction ());
682
+ BlockSetVector functionBlocks (asi->getFunction ());
608
683
609
684
// Insert all of the blocks that asi is live in.
610
685
for (auto *use : asi->getUses ())
@@ -625,7 +700,7 @@ void StackAllocationPromoter::promoteAllocationToPhi() {
625
700
LLVM_DEBUG (llvm::dbgs () << " *** Placing Phis for : " << *asi);
626
701
627
702
// A list of blocks that will require new Phi values.
628
- BlockSet phiBlocks (asi->getFunction ());
703
+ BlockSetVector phiBlocks (asi->getFunction ());
629
704
630
705
// The "piggy-bank" data-structure that we use for processing the dom-tree
631
706
// bottom-up.
@@ -1028,6 +1103,12 @@ bool MemoryToRegisters::promoteSingleAllocation(
1028
1103
LLVM_DEBUG (llvm::dbgs () << " *** Memory to register looking at: " << *alloc);
1029
1104
++NumAllocStackFound;
1030
1105
1106
+ // In OSSA, don't do Mem2Reg on non-trivial alloc_stack with dynamic_lifetime.
1107
+ if (alloc->hasDynamicLifetime () && f.hasOwnership () &&
1108
+ !alloc->getType ().isTrivial (f)) {
1109
+ return false ;
1110
+ }
1111
+
1031
1112
// Don't handle captured AllocStacks.
1032
1113
bool inSingleBlock = false ;
1033
1114
if (isCaptured (alloc, inSingleBlock)) {
0 commit comments