Skip to content

Commit 8c63134

Browse files
Merge pull request #78682 from nate-chandler/rdar142636711_2
[TempRValueOpt] Invalidate insts when completing.
2 parents ca751cb + 8fb0fd2 commit 8c63134

File tree

7 files changed

+210
-119
lines changed

7 files changed

+210
-119
lines changed

include/swift/SILOptimizer/PassManager/PassManager.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,9 @@ class SILPassManager {
444444

445445
void executePassPipelinePlan(const SILPassPipelinePlan &Plan);
446446

447-
bool continueWithNextSubpassRun(SILInstruction *forInst, SILFunction *function,
448-
SILTransform *trans);
447+
using Transformee = llvm::PointerUnion<SILValue, SILInstruction *>;
448+
bool continueWithNextSubpassRun(std::optional<Transformee> forTransformee,
449+
SILFunction *function, SILTransform *trans);
449450

450451
static bool isPassDisabled(StringRef passName);
451452
static bool isInstructionPassDisabled(StringRef instName);

include/swift/SILOptimizer/PassManager/Transforms.h

+4
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ namespace swift {
133133
return PM->continueWithNextSubpassRun(forInst, F, this);
134134
}
135135

136+
bool continueWithNextSubpassRun(SILValue forValue) {
137+
return PM->continueWithNextSubpassRun(forValue, F, this);
138+
}
139+
136140
void invalidateAnalysis(SILAnalysis::InvalidationKind K) {
137141
PM->invalidateAnalysis(F, K);
138142
}

lib/SIL/IR/SILInstruction.cpp

+37-34
Original file line numberDiff line numberDiff line change
@@ -1834,41 +1834,35 @@ visitRecursivelyLifetimeEndingUses(
18341834
llvm::function_ref<bool(Operand *)> visitScopeEnd,
18351835
llvm::function_ref<bool(Operand *)> visitUnknownUse) {
18361836

1837-
for (Operand *use : i->getConsumingUses()) {
1838-
noUsers = false;
1839-
if (isa<DestroyValueInst>(use->getUser())) {
1840-
if (!visitScopeEnd(use)) {
1841-
return false;
1837+
StackList<SILValue> values(i->getFunction());
1838+
values.push_back(i);
1839+
1840+
while (!values.empty()) {
1841+
auto value = values.pop_back_val();
1842+
for (Operand *use : value->getConsumingUses()) {
1843+
noUsers = false;
1844+
if (isa<DestroyValueInst>(use->getUser())) {
1845+
if (!visitScopeEnd(use)) {
1846+
return false;
1847+
}
1848+
continue;
18421849
}
1843-
continue;
1844-
}
1845-
if (auto *ret = dyn_cast<ReturnInst>(use->getUser())) {
1846-
auto fnTy = ret->getFunction()->getLoweredFunctionType();
1847-
assert(!fnTy->getLifetimeDependencies().empty());
1848-
if (!visitScopeEnd(use)) {
1849-
return false;
1850+
if (auto *ret = dyn_cast<ReturnInst>(use->getUser())) {
1851+
auto fnTy = ret->getFunction()->getLoweredFunctionType();
1852+
assert(!fnTy->getLifetimeDependencies().empty());
1853+
if (!visitScopeEnd(use)) {
1854+
return false;
1855+
}
1856+
continue;
18501857
}
1851-
continue;
1852-
}
1853-
// FIXME: Handle store to indirect result
1854-
1855-
// There shouldn't be any dead-end consumptions of a nonescaping
1856-
// partial_apply that don't forward it along, aside from destroy_value.
1857-
//
1858-
// On-stack partial_apply cannot be cloned, so it should never be used by a
1859-
// BranchInst.
1860-
//
1861-
// This is a fatal error because it performs SIL verification that is not
1862-
// separately checked in the verifier. It is the only check that verifies
1863-
// the structural requirements of on-stack partial_apply uses.
1864-
auto *user = use->getUser();
1865-
if (user->getNumResults() == 0) {
1866-
return visitUnknownUse(use);
1867-
}
1868-
for (auto res : use->getUser()->getResults()) {
1869-
if (!visitRecursivelyLifetimeEndingUses(res, noUsers, visitScopeEnd,
1870-
visitUnknownUse)) {
1871-
return false;
1858+
// FIXME: Handle store to indirect result
1859+
1860+
auto *user = use->getUser();
1861+
if (user->getNumResults() == 0) {
1862+
return visitUnknownUse(use);
1863+
}
1864+
for (auto res : use->getUser()->getResults()) {
1865+
values.push_back(res);
18721866
}
18731867
}
18741868
}
@@ -1883,7 +1877,16 @@ PartialApplyInst::visitOnStackLifetimeEnds(
18831877
&& "only meaningful for OSSA stack closures");
18841878
bool noUsers = true;
18851879

1886-
auto visitUnknownUse = [](Operand *unknownUse){
1880+
auto visitUnknownUse = [](Operand *unknownUse) {
1881+
// There shouldn't be any dead-end consumptions of a nonescaping
1882+
// partial_apply that don't forward it along, aside from destroy_value.
1883+
//
1884+
// On-stack partial_apply cannot be cloned, so it should never be used by a
1885+
// BranchInst.
1886+
//
1887+
// This is a fatal error because it performs SIL verification that is not
1888+
// separately checked in the verifier. It is the only check that verifies
1889+
// the structural requirements of on-stack partial_apply uses.
18871890
llvm::errs() << "partial_apply [on_stack] use:\n";
18881891
auto *user = unknownUse->getUser();
18891892
user->printInContext(llvm::errs());

lib/SILOptimizer/PassManager/PassManager.cpp

+36-9
Original file line numberDiff line numberDiff line change
@@ -488,16 +488,35 @@ bool SILPassManager::continueTransforming() {
488488
return NumPassesRun < maxNumPassesToRun;
489489
}
490490

491-
bool SILPassManager::continueWithNextSubpassRun(SILInstruction *forInst,
492-
SILFunction *function,
493-
SILTransform *trans) {
491+
bool SILPassManager::continueWithNextSubpassRun(
492+
std::optional<Transformee> origTransformee, SILFunction *function,
493+
SILTransform *trans) {
494+
// Rewrite .some(nullptr) as .none.
495+
std::optional<llvm::PointerUnion<SILValue, SILInstruction *>> forTransformee;
496+
if (origTransformee) {
497+
auto forValue = dyn_cast<SILValue>(*origTransformee);
498+
if (forValue) {
499+
forTransformee = forValue;
500+
} else if (auto *forInst = cast<SILInstruction *>(*origTransformee)) {
501+
forTransformee = forInst;
502+
}
503+
}
504+
494505
unsigned subPass = numSubpassesRun++;
495506

496-
if (forInst && isFunctionSelectedForPrinting(function) &&
497-
SILPrintEverySubpass) {
507+
if (isFunctionSelectedForPrinting(function) && SILPrintEverySubpass) {
498508
dumpPassInfo("*** SIL function before ", trans, function);
499-
if (forInst) {
500-
llvm::dbgs() << " *** sub-pass " << subPass << " for " << *forInst;
509+
llvm::dbgs() << " *** sub-pass " << subPass << " for ";
510+
if (forTransformee) {
511+
auto forValue = dyn_cast<SILValue>(*forTransformee);
512+
if (forValue) {
513+
llvm::dbgs() << forValue;
514+
} else {
515+
auto *forInst = cast<SILInstruction *>(*forTransformee);
516+
llvm::dbgs() << *forInst;
517+
}
518+
} else {
519+
llvm::dbgs() << "???\n";
501520
}
502521
function->dump(getOptions().EmitVerboseSIL);
503522
}
@@ -509,8 +528,16 @@ bool SILPassManager::continueWithNextSubpassRun(SILInstruction *forInst,
509528

510529
if (subPass == maxNumSubpassesToRun - 1 && SILPrintLast) {
511530
dumpPassInfo("*** SIL function before ", trans, function);
512-
if (forInst) {
513-
llvm::dbgs() << " *** sub-pass " << subPass << " for " << *forInst;
531+
if (forTransformee) {
532+
auto forValue = dyn_cast<SILValue>(*forTransformee);
533+
if (forValue) {
534+
llvm::dbgs() << forValue;
535+
} else {
536+
auto *forInst = cast<SILInstruction *>(*forTransformee);
537+
llvm::dbgs() << *forInst;
538+
}
539+
} else {
540+
llvm::dbgs() << "???\n";
514541
}
515542
function->dump(getOptions().EmitVerboseSIL);
516543
}

lib/SILOptimizer/Transforms/CopyPropagation.cpp

+54-20
Original file line numberDiff line numberDiff line change
@@ -443,38 +443,26 @@ class CopyPropagation : public SILFunctionTransform {
443443
/// The entry point to this function transformation.
444444
void run() override;
445445

446+
void propagateCopies(CanonicalDefWorklist &defWorklist, bool &changed,
447+
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
448+
InstructionDeleter &deleter);
449+
446450
void verifyOwnership();
447451
};
448452

449453
} // end anonymous namespace
450454

451-
/// Top-level pass driver.
452-
void CopyPropagation::run() {
455+
void CopyPropagation::propagateCopies(
456+
CanonicalDefWorklist &defWorklist, bool &changed,
457+
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
458+
InstructionDeleter &deleter) {
453459
auto *f = getFunction();
454460
auto *postOrderAnalysis = getAnalysis<PostOrderAnalysis>();
455-
auto *accessBlockAnalysis = getAnalysis<NonLocalAccessBlockAnalysis>();
456461
auto *deadEndBlocksAnalysis = getAnalysis<DeadEndBlocksAnalysis>();
457462
auto *dominanceAnalysis = getAnalysis<DominanceAnalysis>();
458463
auto *calleeAnalysis = getAnalysis<BasicCalleeAnalysis>();
459464
DominanceInfo *domTree = dominanceAnalysis->get(f);
460465

461-
// Label for unit testing with debug output.
462-
LLVM_DEBUG(llvm::dbgs() << "*** CopyPropagation: " << f->getName() << "\n");
463-
464-
// This algorithm fundamentally assumes ownership.
465-
if (!f->hasOwnership())
466-
return;
467-
468-
CanonicalDefWorklist defWorklist(canonicalizeBorrows);
469-
auto callbacks =
470-
InstModCallbacks().onDelete([&](SILInstruction *instToDelete) {
471-
defWorklist.erase(instToDelete);
472-
instToDelete->eraseFromParent();
473-
});
474-
475-
InstructionDeleter deleter(std::move(callbacks));
476-
bool changed = false;
477-
478466
StackList<BeginBorrowInst *> beginBorrowsToShrink(f);
479467
StackList<MoveValueInst *> moveValues(f);
480468

@@ -514,6 +502,8 @@ void CopyPropagation::run() {
514502
// at least once and then until each stops making changes.
515503
while (true) {
516504
SmallVector<CopyValueInst *, 4> modifiedCopyValueInsts;
505+
if (!continueWithNextSubpassRun(bbi))
506+
return;
517507
auto shrunk = shrinkBorrowScope(*bbi, deleter, calleeAnalysis,
518508
modifiedCopyValueInsts);
519509
for (auto *cvi : modifiedCopyValueInsts)
@@ -528,25 +518,35 @@ void CopyPropagation::run() {
528518
if (borrowee->getOwnershipKind() != OwnershipKind::Owned)
529519
break;
530520

521+
if (!continueWithNextSubpassRun(borrowee))
522+
return;
531523
auto canonicalized = canonicalizer.canonicalizeValueLifetime(borrowee);
532524
if (!canonicalized && !firstRun)
533525
break;
534526

527+
if (!continueWithNextSubpassRun(bbi))
528+
return;
535529
auto folded = foldDestroysOfCopiedLexicalBorrow(bbi, *domTree, deleter);
536530
if (!folded)
537531
break;
538532
auto hoisted = canonicalizer.canonicalizeValueLifetime(folded);
539533
// Keep running even if the new move's destroys can't be hoisted.
540534
(void)hoisted;
535+
if (!continueWithNextSubpassRun(folded))
536+
return;
541537
eliminateRedundantMove(folded, deleter, defWorklist);
542538
firstRun = false;
543539
}
544540
}
545541
for (auto *mvi : moveValues) {
542+
if (!continueWithNextSubpassRun(mvi))
543+
return;
546544
eliminateRedundantMove(mvi, deleter, defWorklist);
547545
}
548546
for (auto *argument : f->getArguments()) {
549547
if (argument->getOwnershipKind() == OwnershipKind::Owned) {
548+
if (!continueWithNextSubpassRun(argument))
549+
return;
550550
canonicalizer.canonicalizeValueLifetime(argument);
551551
}
552552
}
@@ -584,8 +584,12 @@ void CopyPropagation::run() {
584584
// they may be chained, and CanonicalizeBorrowScopes pushes them
585585
// top-down.
586586
for (auto result : ownedForward->getResults()) {
587+
if (!continueWithNextSubpassRun(result))
588+
return;
587589
canonicalizer.canonicalizeValueLifetime(result);
588590
}
591+
if (!continueWithNextSubpassRun(ownedForward))
592+
return;
589593
if (sinkOwnedForward(ownedForward, postOrderAnalysis, domTree)) {
590594
changed = true;
591595
// Sinking 'ownedForward' may create an opportunity to sink its
@@ -607,6 +611,8 @@ void CopyPropagation::run() {
607611
BorrowedValue borrow(defWorklist.borrowedValues.pop_back_val());
608612
assert(canonicalizeBorrows || !borrow.isLocalScope());
609613

614+
if (!continueWithNextSubpassRun(borrow.value))
615+
return;
610616
borrowCanonicalizer.canonicalizeBorrowScope(borrow);
611617
for (CopyValueInst *copy : borrowCanonicalizer.getUpdatedCopies()) {
612618
defWorklist.updateForCopy(copy);
@@ -623,13 +629,41 @@ void CopyPropagation::run() {
623629
// Canonicalize all owned defs.
624630
while (!defWorklist.ownedValues.empty()) {
625631
SILValue def = defWorklist.ownedValues.pop_back_val();
632+
if (!continueWithNextSubpassRun(def))
633+
return;
626634
auto canonicalized = canonicalizer.canonicalizeValueLifetime(def);
627635
if (!canonicalized)
628636
continue;
629637
// Copies of borrowed values may be dead.
630638
if (auto *inst = def->getDefiningInstruction())
631639
deleter.trackIfDead(inst);
632640
}
641+
}
642+
643+
/// Top-level pass driver.
644+
void CopyPropagation::run() {
645+
auto *f = getFunction();
646+
// This algorithm fundamentally assumes ownership.
647+
if (!f->hasOwnership())
648+
return;
649+
650+
// Label for unit testing with debug output.
651+
LLVM_DEBUG(llvm::dbgs() << "*** CopyPropagation: " << f->getName() << "\n");
652+
653+
auto *accessBlockAnalysis = getAnalysis<NonLocalAccessBlockAnalysis>();
654+
655+
CanonicalDefWorklist defWorklist(canonicalizeBorrows);
656+
657+
auto callbacks =
658+
InstModCallbacks().onDelete([&](SILInstruction *instToDelete) {
659+
defWorklist.erase(instToDelete);
660+
instToDelete->eraseFromParent();
661+
});
662+
InstructionDeleter deleter(std::move(callbacks));
663+
664+
bool changed = false;
665+
propagateCopies(defWorklist, changed, accessBlockAnalysis, deleter);
666+
633667
// Recursively cleanup dead defs after removing uses.
634668
deleter.cleanupDeadInstructions();
635669

0 commit comments

Comments
 (0)