Skip to content

Commit fcafbc1

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 24a871b commit fcafbc1

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
@@ -288,6 +288,19 @@ class StackAllocationPromoter {
288288
/// Replace the dummy nodes with new block arguments.
289289
void addBlockArguments(BlockSetVector &phiBlocks);
290290

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);
303+
291304
/// Fix all of the branch instructions and the uses to use
292305
/// the AllocStack definitions (which include stores and Phis).
293306
void fixBranchesAndUses(BlockSetVector &blocks);
@@ -522,6 +535,52 @@ void StackAllocationPromoter::fixPhiPredBlock(BlockSetVector &phiBlocks,
522535
ti->eraseFromParent();
523536
}
524537

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+
525584
void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
526585
// First update uses of the value.
527586
SmallVector<LoadInst *, 4> collectedLoads;
@@ -577,7 +636,6 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
577636

578637
// Now that all of the uses are fixed we can fix the branches that point
579638
// to the blocks with the added arguments.
580-
581639
// For each Block with a new Phi argument:
582640
for (auto *block : phiBlocks) {
583641
// Fix all predecessors.
@@ -591,14 +649,30 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
591649
}
592650
}
593651

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

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)