Skip to content

Commit 419d87d

Browse files
Merge pull request #78105 from nate-chandler/rdar141197164
[SILGenCleanup] Complete lifetimes of defs backwards reachable from dead-end blocks.
2 parents 2120a7f + c327c59 commit 419d87d

File tree

7 files changed

+482
-45
lines changed

7 files changed

+482
-45
lines changed

include/swift/SIL/BasicBlockDatastructures.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class BasicBlockWorklist {
8383
push(initialBlock);
8484
}
8585

86+
/// Whether there are any remaining blocks to process.
87+
bool empty() { return worklist.empty(); }
88+
8689
/// Pops the last added element from the worklist or returns null, if the
8790
/// worklist is empty.
8891
SILBasicBlock *pop() {

include/swift/SIL/SILFunction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,17 @@ class SILFunction
15651565
}
15661566
}
15671567

1568+
/// Populate \p output with every block terminated by an unreachable
1569+
/// instruction.
1570+
void visitUnreachableTerminatedBlocks(
1571+
llvm::function_ref<void(SILBasicBlock &)> visitor) const {
1572+
for (auto &block : const_cast<SILFunction &>(*this)) {
1573+
if (isa<UnreachableInst>(block.getTerminator())) {
1574+
visitor(block);
1575+
}
1576+
}
1577+
}
1578+
15681579
//===--------------------------------------------------------------------===//
15691580
// Argument Helper Methods
15701581
//===--------------------------------------------------------------------===//

include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,32 @@ class SILLoopInfo;
3838
/// Compute the set of reachable blocks.
3939
class ReachableBlocks {
4040
BasicBlockSet visited;
41+
bool isComputed;
4142

4243
public:
43-
ReachableBlocks(SILFunction *function) : visited(function) {}
44+
ReachableBlocks(SILFunction *function)
45+
: visited(function), isComputed(false) {}
4446

47+
/// Populate `visited` with the blocks reachable in the function.
48+
void compute();
49+
50+
/// Whether `block` is reachable from the entry block.
51+
bool isReachable(SILBasicBlock *block) const {
52+
assert(isComputed);
53+
return visited.contains(block);
54+
}
55+
56+
bool hasUnreachableBlocks() const {
57+
assert(isComputed);
58+
for (auto &block : *visited.getFunction()) {
59+
if (!isReachable(&block)) {
60+
return true;
61+
}
62+
}
63+
return false;
64+
}
65+
66+
private:
4567
/// Invoke \p visitor for each reachable block in \p f in worklist order (at
4668
/// least one predecessor has been visited--defs are always visited before
4769
/// uses except for phi-type block args). The \p visitor takes a block
@@ -50,9 +72,6 @@ class ReachableBlocks {
5072
///
5173
/// Returns true if all reachable blocks were visited.
5274
bool visit(function_ref<bool(SILBasicBlock *)> visitor);
53-
54-
/// Return true if \p bb has been visited.
55-
bool isVisited(SILBasicBlock *bb) const { return visited.contains(bb); }
5675
};
5776

5877
/// Computes the set of blocks from which a path to the return-block exists.

lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,7 @@ static SILValue tryRewriteToPartialApplyStack(
587587
ConvertEscapeToNoEscapeInst *cvt, SILInstruction *closureUser,
588588
DominanceAnalysis *dominanceAnalysis, InstructionDeleter &deleter,
589589
llvm::DenseMap<SILInstruction *, SILInstruction *> &memoized,
590-
llvm::DenseSet<SILBasicBlock *> &unreachableBlocks,
591-
const bool &modifiedCFG) {
590+
ReachableBlocks const &reachableBlocks, const bool &modifiedCFG) {
592591

593592
auto *origPA = dyn_cast<PartialApplyInst>(skipConvert(cvt->getOperand()));
594593
if (!origPA)
@@ -972,8 +971,8 @@ static SILValue tryRewriteToPartialApplyStack(
972971

973972
// Don't run insertDeallocOfCapturedArguments if newPA is in an unreachable
974973
// block insertDeallocOfCapturedArguments will run code that computes the DF
975-
// for newPA that will loop infinetly.
976-
if (unreachableBlocks.count(newPA->getParent()))
974+
// for newPA that will loop infinitely.
975+
if (!reachableBlocks.isReachable(newPA->getParent()))
977976
return closureOp;
978977

979978
auto getAddressToDealloc = [&](SILValue argAddress) -> SILValue {
@@ -995,8 +994,8 @@ static bool tryExtendLifetimeToLastUse(
995994
ConvertEscapeToNoEscapeInst *cvt, DominanceAnalysis *dominanceAnalysis,
996995
DeadEndBlocksAnalysis *deadEndBlocksAnalysis,
997996
llvm::DenseMap<SILInstruction *, SILInstruction *> &memoized,
998-
llvm::DenseSet<SILBasicBlock *> &unreachableBlocks,
999-
InstructionDeleter &deleter, const bool &modifiedCFG) {
997+
ReachableBlocks const &reachableBlocks, InstructionDeleter &deleter,
998+
const bool &modifiedCFG) {
1000999
// If there is a single user, this is simple: extend the
10011000
// lifetime of the operand until the use ends.
10021001
auto *singleUser = lookThroughRebastractionUsers(cvt, memoized);
@@ -1019,7 +1018,7 @@ static bool tryExtendLifetimeToLastUse(
10191018

10201019
if (SILValue closureOp = tryRewriteToPartialApplyStack(
10211020
cvt, singleUser, dominanceAnalysis, deleter, memoized,
1022-
unreachableBlocks, /*const*/ modifiedCFG)) {
1021+
reachableBlocks, /*const*/ modifiedCFG)) {
10231022
if (endAsyncLet) {
10241023
// Add the closure as a second operand to the endAsyncLet builtin.
10251024
// This ensures that the closure arguments are kept alive until the
@@ -1428,22 +1427,6 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
14281427
return true;
14291428
}
14301429

1431-
static void computeUnreachableBlocks(
1432-
llvm::DenseSet<SILBasicBlock*> &unreachableBlocks,
1433-
SILFunction &fn) {
1434-
1435-
ReachableBlocks isReachable(&fn);
1436-
llvm::DenseSet<SILBasicBlock *> reachable;
1437-
isReachable.visit([&] (SILBasicBlock *block) -> bool {
1438-
reachable.insert(block);
1439-
return true;
1440-
});
1441-
for (auto &block : fn) {
1442-
if (!reachable.count(&block))
1443-
unreachableBlocks.insert(&block);
1444-
}
1445-
}
1446-
14471430
static bool fixupClosureLifetimes(SILFunction &fn,
14481431
DominanceAnalysis *dominanceAnalysis,
14491432
DeadEndBlocksAnalysis *deadEndBlocksAnalysis,
@@ -1454,8 +1437,8 @@ static bool fixupClosureLifetimes(SILFunction &fn,
14541437
// queries.
14551438
llvm::DenseMap<SILInstruction *, SILInstruction *> memoizedQueries;
14561439

1457-
llvm::DenseSet<SILBasicBlock *> unreachableBlocks;
1458-
computeUnreachableBlocks(unreachableBlocks, fn);
1440+
ReachableBlocks reachableBlocks(&fn);
1441+
reachableBlocks.compute();
14591442

14601443
for (auto &block : fn) {
14611444
SILSSAUpdater updater;
@@ -1485,7 +1468,7 @@ static bool fixupClosureLifetimes(SILFunction &fn,
14851468

14861469
if (tryExtendLifetimeToLastUse(cvt, dominanceAnalysis,
14871470
deadEndBlocksAnalysis, memoizedQueries,
1488-
unreachableBlocks, updater.getDeleter(),
1471+
reachableBlocks, updater.getDeleter(),
14891472
/*const*/ modifiedCFG)) {
14901473
changed = true;
14911474
checkStackNesting = true;

0 commit comments

Comments
 (0)