Skip to content

Commit 5cb144f

Browse files
authored
Merge pull request #38265 from meg-gupta/alternatemem2regfix2
Cleanup dead phis in SILMem2Reg for OSSA
2 parents e627318 + dc57d6b commit 5cb144f

File tree

3 files changed

+464
-25
lines changed

3 files changed

+464
-25
lines changed

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ namespace {
228228

229229
/// Promotes a single AllocStackInst into registers..
230230
class 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

610685
void 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)) {

test/SILOptimizer/mem2reg.sil

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,11 @@ bb0(%0 : $Optional<Klass>):
466466
return %4 : $()
467467
}
468468

469-
// check no dead args are passed to bb3
469+
// dead args okay in non-ossa
470470
// CHECK-LABEL: sil @multi_basic_block_use_on_one_path :
471471
// CHECK-NOT: alloc_stack
472-
// CHECK: bb3:
473-
// CHECK-LABEL: } // end sil function 'multi_basic_block_use_on_one_path'
472+
// CHECK: br bb3(undef : $Klass)
473+
// CHECK: bb3([[dead_arg:%.*]]):
474474
sil @multi_basic_block_use_on_one_path : $@convention(thin) (@owned Klass) -> () {
475475
bb0(%0 : $Klass):
476476
%1 = alloc_stack $Klass

0 commit comments

Comments
 (0)