Skip to content

Commit dc0f53d

Browse files
authored
Merge pull request #38342 from meg-gupta/fixcleanup55
[5.5] Cleanup dead phis in SILMem2Reg for OSSA
2 parents 3420469 + e2a18a6 commit dc0f53d

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
@@ -226,7 +226,7 @@ namespace {
226226

227227
/// Promotes a single AllocStackInst into registers..
228228
class StackAllocationPromoter {
229-
using BlockSet = BasicBlockSetVector;
229+
using BlockSetVector = BasicBlockSetVector;
230230
using BlockToInstMap = llvm::DenseMap<SILBasicBlock *, SILInstruction *>;
231231

232232
// Use a priority queue keyed on dominator tree level so that inserted nodes
@@ -286,26 +286,40 @@ class StackAllocationPromoter {
286286
void promoteAllocationToPhi();
287287

288288
/// 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);
290303

291304
/// Fix all of the branch instructions and the uses to use
292305
/// the AllocStack definitions (which include stores and Phis).
293-
void fixBranchesAndUses(BlockSet &blocks);
306+
void fixBranchesAndUses(BlockSetVector &blocks);
294307

295308
/// update the branch instructions with the new Phi argument.
296309
/// The blocks in \p PhiBlocks are blocks that define a value, \p Dest is
297310
/// the branch destination, and \p Pred is the predecessors who's branch we
298311
/// modify.
299-
void fixPhiPredBlock(BlockSet &phiBlocks, SILBasicBlock *dest,
312+
void fixPhiPredBlock(BlockSetVector &phiBlocks, SILBasicBlock *dest,
300313
SILBasicBlock *pred);
301314

302315
/// Get the value for this AllocStack variable that is
303316
/// flowing out of StartBB.
304-
SILValue getLiveOutValue(BlockSet &phiBlocks, SILBasicBlock *startBlock);
317+
SILValue getLiveOutValue(BlockSetVector &phiBlocks,
318+
SILBasicBlock *startBlock);
305319

306320
/// Get the value for this AllocStack variable that is
307321
/// flowing into BB.
308-
SILValue getLiveInValue(BlockSet &phiBlocks, SILBasicBlock *block);
322+
SILValue getLiveInValue(BlockSetVector &phiBlocks, SILBasicBlock *block);
309323

310324
/// Prune AllocStacks usage in the function. Scan the function
311325
/// and remove in-block usage of the AllocStack. Leave only the first
@@ -445,14 +459,14 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
445459
return lastStore;
446460
}
447461

448-
void StackAllocationPromoter::addBlockArguments(BlockSet &phiBlocks) {
462+
void StackAllocationPromoter::addBlockArguments(BlockSetVector &phiBlocks) {
449463
LLVM_DEBUG(llvm::dbgs() << "*** Adding new block arguments.\n");
450464

451465
for (auto *block : phiBlocks)
452466
block->createPhiArgument(asi->getElementType(), OwnershipKind::Owned);
453467
}
454468

455-
SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
469+
SILValue StackAllocationPromoter::getLiveOutValue(BlockSetVector &phiBlocks,
456470
SILBasicBlock *startBlock) {
457471
LLVM_DEBUG(llvm::dbgs() << "*** Searching for a value definition.\n");
458472
// Walk the Dom tree in search of a defining value:
@@ -484,7 +498,7 @@ SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &phiBlocks,
484498
return SILUndef::get(asi->getElementType(), *asi->getFunction());
485499
}
486500

487-
SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
501+
SILValue StackAllocationPromoter::getLiveInValue(BlockSetVector &phiBlocks,
488502
SILBasicBlock *block) {
489503
// First, check if there is a Phi value in the current block. We know that
490504
// our loads happen before stores, so we need to first check for Phi nodes
@@ -507,7 +521,7 @@ SILValue StackAllocationPromoter::getLiveInValue(BlockSet &phiBlocks,
507521
return getLiveOutValue(phiBlocks, iDom->getBlock());
508522
}
509523

510-
void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
524+
void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
511525
SILBasicBlock *destBlock,
512526
SILBasicBlock *predBlock) {
513527
TermInst *ti = predBlock->getTerminator();
@@ -521,7 +535,53 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSet &phiBlocks,
521535
ti->eraseFromParent();
522536
}
523537

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) {
525585
// First update uses of the value.
526586
SmallVector<LoadInst *, 4> collectedLoads;
527587

@@ -576,7 +636,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
576636

577637
// Now that all of the uses are fixed we can fix the branches that point
578638
// to the blocks with the added arguments.
579-
580639
// For each Block with a new Phi argument:
581640
for (auto *block : phiBlocks) {
582641
// Fix all predecessors.
@@ -590,21 +649,37 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSet &phiBlocks) {
590649
}
591650
}
592651

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+
}
601676
}
602677
}
603678
}
604679

605680
void StackAllocationPromoter::pruneAllocStackUsage() {
606681
LLVM_DEBUG(llvm::dbgs() << "*** Pruning : " << *asi);
607-
BlockSet functionBlocks(asi->getFunction());
682+
BlockSetVector functionBlocks(asi->getFunction());
608683

609684
// Insert all of the blocks that asi is live in.
610685
for (auto *use : asi->getUses())
@@ -625,7 +700,7 @@ void StackAllocationPromoter::promoteAllocationToPhi() {
625700
LLVM_DEBUG(llvm::dbgs() << "*** Placing Phis for : " << *asi);
626701

627702
// A list of blocks that will require new Phi values.
628-
BlockSet phiBlocks(asi->getFunction());
703+
BlockSetVector phiBlocks(asi->getFunction());
629704

630705
// The "piggy-bank" data-structure that we use for processing the dom-tree
631706
// bottom-up.
@@ -1028,6 +1103,12 @@ bool MemoryToRegisters::promoteSingleAllocation(
10281103
LLVM_DEBUG(llvm::dbgs() << "*** Memory to register looking at: " << *alloc);
10291104
++NumAllocStackFound;
10301105

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+
10311112
// Don't handle captured AllocStacks.
10321113
bool inSingleBlock = false;
10331114
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)