Skip to content

Commit b08a3b7

Browse files
author
Harlan
authored
[SILOptimizer] Clean up infinite recursion diagnostic pass (#19710)
* [SILOptimizer] Clean up infinite recursion diagnostic pass NFC. This cleans up the pass to avoid the extra lambda and to clear up the ordering of what check is supposed to come before what. * Address review comments
1 parent 3c2096f commit b08a3b7

File tree

1 file changed

+27
-25
lines changed

1 file changed

+27
-25
lines changed

lib/SILOptimizer/Mandatory/DiagnoseInfiniteRecursion.cpp

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,37 +94,39 @@ static bool hasRecursiveCallInPath(SILBasicBlock &Block,
9494
return false;
9595
}
9696

97-
static bool hasInfinitelyRecursiveApply(SILFunction &Fn,
98-
SILFunction *TargetFn) {
99-
SmallPtrSet<SILBasicBlock *, 16> Visited;
100-
SmallVector<SILBasicBlock *, 16> WorkList;
101-
// Keep track of whether we found at least one recursive path.
97+
/// Perform a DFS through the target function to find any paths to an exit node
98+
/// that do not call into the target.
99+
static bool hasInfinitelyRecursiveApply(SILFunction *targetFn) {
100+
SmallPtrSet<SILBasicBlock *, 32> visited = { targetFn->getEntryBlock() };
101+
SmallVector<SILBasicBlock *, 32> workList = { targetFn->getEntryBlock() };
102+
103+
// Keep track of if we've found any recursive blocks at all.
104+
// We return true if we found any recursion and did not find any
105+
// non-recursive, function-exiting blocks.
102106
bool foundRecursion = false;
107+
auto *targetModule = targetFn->getModule().getSwiftModule();
103108

104-
auto *TargetModule = TargetFn->getModule().getSwiftModule();
105-
auto analyzeSuccessor = [&](SILBasicBlock *Succ) -> bool {
106-
if (!Visited.insert(Succ).second)
107-
return false;
109+
while (!workList.empty()) {
110+
SILBasicBlock *curBlock = workList.pop_back_val();
108111

109-
// If the successor block contains a recursive call, end analysis there.
110-
if (!hasRecursiveCallInPath(*Succ, TargetFn, TargetModule)) {
111-
WorkList.push_back(Succ);
112-
return false;
112+
// We're looking for functions that are recursive on _all_ paths. If this
113+
// block is recursive, mark that we found recursion and check the next
114+
// block in the work list.
115+
if (hasRecursiveCallInPath(*curBlock, targetFn, targetModule)) {
116+
foundRecursion = true;
117+
continue;
113118
}
114-
return true;
115-
};
116119

117-
// Seed the work list with the entry block.
118-
foundRecursion |= analyzeSuccessor(Fn.getEntryBlock());
119-
120-
while (!WorkList.empty()) {
121-
SILBasicBlock *CurBlock = WorkList.pop_back_val();
122-
// Found a path to the exit node without a recursive call.
123-
if (CurBlock->getTerminator()->isFunctionExiting())
120+
// If this block doesn't have a recursive call, and it exits the function,
121+
// then we know the function is not infinitely recursive.
122+
if (curBlock->getTerminator()->isFunctionExiting())
124123
return false;
125124

126-
for (SILBasicBlock *Succ : CurBlock->getSuccessorBlocks())
127-
foundRecursion |= analyzeSuccessor(Succ);
125+
// Otherwise, push the successors onto the stack if we haven't visited them.
126+
for (auto *succ : curBlock->getSuccessorBlocks()) {
127+
if (visited.insert(succ).second)
128+
workList.push_back(succ);
129+
}
128130
}
129131
return foundRecursion;
130132
}
@@ -149,7 +151,7 @@ namespace {
149151
if (!Fn->hasLocation() || Fn->getLocation().getSourceLoc().isInvalid())
150152
return;
151153

152-
if (hasInfinitelyRecursiveApply(*Fn, Fn)) {
154+
if (hasInfinitelyRecursiveApply(Fn)) {
153155
diagnose(Fn->getModule().getASTContext(),
154156
Fn->getLocation().getSourceLoc(),
155157
diag::warn_infinite_recursive_function);

0 commit comments

Comments
 (0)