@@ -228,7 +228,7 @@ namespace {
228
228
229
229
// / Promotes a single AllocStackInst into registers..
230
230
class StackAllocationPromoter {
231
- using BlockSet = BasicBlockSetVector;
231
+ using BlockSetVector = BasicBlockSetVector;
232
232
using BlockToInstMap = llvm::DenseMap<SILBasicBlock *, SILInstruction *>;
233
233
234
234
// Use a priority queue keyed on dominator tree level so that inserted nodes
@@ -291,26 +291,40 @@ class StackAllocationPromoter {
291
291
void promoteAllocationToPhi ();
292
292
293
293
// / 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);
295
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
- void fixBranchesAndUses (BlockSet &blocks);
311
+ void fixBranchesAndUses (BlockSetVector &blocks);
299
312
300
313
// / update the branch instructions with the new Phi argument.
301
314
// / The blocks in \p PhiBlocks are blocks that define a value, \p Dest is
302
315
// / the branch destination, and \p Pred is the predecessors who's branch we
303
316
// / modify.
304
- void fixPhiPredBlock (BlockSet &phiBlocks, SILBasicBlock *dest,
317
+ void fixPhiPredBlock (BlockSetVector &phiBlocks, SILBasicBlock *dest,
305
318
SILBasicBlock *pred);
306
319
307
320
// / Get the value for this AllocStack variable that is
308
321
// / flowing out of StartBB.
309
- SILValue getLiveOutValue (BlockSet &phiBlocks, SILBasicBlock *startBlock);
322
+ SILValue getLiveOutValue (BlockSetVector &phiBlocks,
323
+ SILBasicBlock *startBlock);
310
324
311
325
// / Get the value for this AllocStack variable that is
312
326
// / flowing into BB.
313
- SILValue getLiveInValue (BlockSet &phiBlocks, SILBasicBlock *block);
327
+ SILValue getLiveInValue (BlockSetVector &phiBlocks, SILBasicBlock *block);
314
328
315
329
// / Prune AllocStacks usage in the function. Scan the function
316
330
// / and remove in-block usage of the AllocStack. Leave only the first
@@ -450,14 +464,14 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
450
464
return lastStore;
451
465
}
452
466
453
- void StackAllocationPromoter::addBlockArguments (BlockSet &phiBlocks) {
467
+ void StackAllocationPromoter::addBlockArguments (BlockSetVector &phiBlocks) {
454
468
LLVM_DEBUG (llvm::dbgs () << " *** Adding new block arguments.\n " );
455
469
456
470
for (auto *block : phiBlocks)
457
471
block->createPhiArgument (asi->getElementType (), OwnershipKind::Owned);
458
472
}
459
473
460
- SILValue StackAllocationPromoter::getLiveOutValue (BlockSet &phiBlocks,
474
+ SILValue StackAllocationPromoter::getLiveOutValue (BlockSetVector &phiBlocks,
461
475
SILBasicBlock *startBlock) {
462
476
LLVM_DEBUG (llvm::dbgs () << " *** Searching for a value definition.\n " );
463
477
// Walk the Dom tree in search of a defining value:
@@ -489,7 +503,7 @@ SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
489
503
return SILUndef::get (asi->getElementType (), *asi->getFunction ());
490
504
}
491
505
492
- SILValue StackAllocationPromoter::getLiveInValue (BlockSet &phiBlocks,
506
+ SILValue StackAllocationPromoter::getLiveInValue (BlockSetVector &phiBlocks,
493
507
SILBasicBlock *block) {
494
508
// First, check if there is a Phi value in the current block. We know that
495
509
// our loads happen before stores, so we need to first check for Phi nodes
@@ -512,7 +526,7 @@ SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
512
526
return getLiveOutValue (phiBlocks, iDom->getBlock ());
513
527
}
514
528
515
- void StackAllocationPromoter::fixPhiPredBlock (BlockSet &phiBlocks,
529
+ void StackAllocationPromoter::fixPhiPredBlock (BlockSetVector &phiBlocks,
516
530
SILBasicBlock *destBlock,
517
531
SILBasicBlock *predBlock) {
518
532
TermInst *ti = predBlock->getTerminator ();
@@ -526,7 +540,53 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
526
540
deleter.forceDelete (ti);
527
541
}
528
542
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) {
530
590
// First update uses of the value.
531
591
SmallVector<LoadInst *, 4 > collectedLoads;
532
592
@@ -581,7 +641,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
581
641
582
642
// Now that all of the uses are fixed we can fix the branches that point
583
643
// to the blocks with the added arguments.
584
-
585
644
// For each Block with a new Phi argument:
586
645
for (auto *block : phiBlocks) {
587
646
// Fix all predecessors.
@@ -595,21 +654,37 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
595
654
}
596
655
}
597
656
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
+ }
606
681
}
607
682
}
608
683
}
609
684
610
685
void StackAllocationPromoter::pruneAllocStackUsage () {
611
686
LLVM_DEBUG (llvm::dbgs () << " *** Pruning : " << *asi);
612
- BlockSet functionBlocks (asi->getFunction ());
687
+ BlockSetVector functionBlocks (asi->getFunction ());
613
688
614
689
// Insert all of the blocks that asi is live in.
615
690
for (auto *use : asi->getUses ())
@@ -630,7 +705,7 @@ void StackAllocationPromoter::promoteAllocationToPhi() {
630
705
LLVM_DEBUG (llvm::dbgs () << " *** Placing Phis for : " << *asi);
631
706
632
707
// A list of blocks that will require new Phi values.
633
- BlockSet phiBlocks (asi->getFunction ());
708
+ BlockSetVector phiBlocks (asi->getFunction ());
634
709
635
710
// The "piggy-bank" data-structure that we use for processing the dom-tree
636
711
// bottom-up.
@@ -1048,6 +1123,12 @@ bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc) {
1048
1123
LLVM_DEBUG (llvm::dbgs () << " *** Memory to register looking at: " << *alloc);
1049
1124
++NumAllocStackFound;
1050
1125
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
+
1051
1132
// Don't handle captured AllocStacks.
1052
1133
bool inSingleBlock = false ;
1053
1134
if (isCaptured (alloc, inSingleBlock)) {
0 commit comments