Skip to content

Commit 42863d4

Browse files
committed
Cleanup dead phis in SILMem2Reg for OSSA
Mem2Reg creates phis proactively that may be unnecessary. Unnecessary phis are those without uses or operands to other proactive phis that are unnecessary. Even though this does not translate to a real issue at runtime, we can see ownership verification errors. This PR identifies such phis and deletes them.
1 parent 2c3f1ac commit 42863d4

File tree

3 files changed

+356
-12
lines changed

3 files changed

+356
-12
lines changed

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,19 @@ class StackAllocationPromoter {
293293
/// Replace the dummy nodes with new block arguments.
294294
void addBlockArguments(BlockSetVector &phiBlocks);
295295

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);
308+
296309
/// Fix all of the branch instructions and the uses to use
297310
/// the AllocStack definitions (which include stores and Phis).
298311
void fixBranchesAndUses(BlockSetVector &blocks);
@@ -527,6 +540,52 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
527540
deleter.forceDelete(ti);
528541
}
529542

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+
530589
void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
531590
// First update uses of the value.
532591
SmallVector<LoadInst *, 4> collectedLoads;
@@ -582,7 +641,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
582641

583642
// Now that all of the uses are fixed we can fix the branches that point
584643
// to the blocks with the added arguments.
585-
586644
// For each Block with a new Phi argument:
587645
for (auto *block : phiBlocks) {
588646
// Fix all predecessors.
@@ -596,14 +654,30 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
596654
}
597655
}
598656

599-
// If the owned phi arg we added did not have any uses, create end_lifetime to
600-
// end its lifetime. In asserts mode, make sure we have only undef incoming
601-
// values for such phi args.
602-
for (auto *block : phiBlocks) {
603-
auto *phiArg =
604-
cast<SILPhiArgument>(block->getArgument(block->getNumArguments() - 1));
605-
if (phiArg->use_empty()) {
606-
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+
}
607681
}
608682
}
609683
}

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)