Skip to content

[4.2] Cleanup dead blocks after noreturn folding #17303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/SILOptimizer/Utils/CFG.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ void completeJointPostDominanceSet(
ArrayRef<SILBasicBlock *> UserBlocks, ArrayRef<SILBasicBlock *> DefBlocks,
llvm::SmallVectorImpl<SILBasicBlock *> &Completion);

/// \brief Remove all unreachable blocks in a function.
bool removeUnreachableBlocks(SILFunction &Fn);

} // end namespace swift

#endif
10 changes: 7 additions & 3 deletions lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "swift/SILOptimizer/Utils/CFG.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
Expand Down Expand Up @@ -750,13 +751,16 @@ static void performNoReturnFunctionProcessing(SILFunction &Fn,
SILFunctionTransform *T) {
DEBUG(llvm::errs() << "*** No return function processing: " << Fn.getName()
<< "\n");

bool Changed = false;
for (auto &BB : Fn) {
// Remove instructions from the basic block after a call to a noreturn
// function.
simplifyBlocksWithCallsToNoReturn(BB, nullptr);
Changed |= simplifyBlocksWithCallsToNoReturn(BB, nullptr);
}
if (Changed) {
removeUnreachableBlocks(Fn);
T->invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
}
T->invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
}

static void diagnoseUnreachable(SILFunction &Fn) {
Expand Down
48 changes: 4 additions & 44 deletions lib/SILOptimizer/Transforms/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,6 @@ namespace {
void findLoopHeaders();
};

class RemoveUnreachable {
SILFunction &Fn;
llvm::SmallSet<SILBasicBlock *, 8> Visited;
public:
RemoveUnreachable(SILFunction &Fn) : Fn(Fn) { }
void visit(SILBasicBlock *BB);
bool run();
};
} // end anonymous namespace

/// Return true if there are any users of V outside the specified block.
Expand Down Expand Up @@ -2161,36 +2153,6 @@ bool SimplifyCFG::simplifyTermWithIdenticalDestBlocks(SILBasicBlock *BB) {
return true;
}

void RemoveUnreachable::visit(SILBasicBlock *BB) {
if (!Visited.insert(BB).second)
return;

for (auto &Succ : BB->getSuccessors())
visit(Succ);
}

bool RemoveUnreachable::run() {
bool Changed = false;

// Clear each time we run so that we can run multiple times.
Visited.clear();

// Visit all blocks reachable from the entry block of the function.
visit(&*Fn.begin());

// Remove the blocks we never reached.
for (auto It = Fn.begin(), End = Fn.end(); It != End; ) {
auto *BB = &*It++;
if (!Visited.count(BB)) {
DEBUG(llvm::dbgs() << "remove unreachable bb" << BB->getDebugID() << '\n');
removeDeadBlock(BB);
Changed = true;
}
}

return Changed;
}

/// Checks if the block contains a cond_fail as first side-effect instruction
/// and tries to move it to the predecessors (if beneficial). A sequence
///
Expand Down Expand Up @@ -2844,10 +2806,8 @@ bool SimplifyCFG::run() {

DEBUG(llvm::dbgs() << "### Run SimplifyCFG on " << Fn.getName() << '\n');

RemoveUnreachable RU(Fn);

// First remove any block not reachable from the entry.
bool Changed = RU.run();
bool Changed = removeUnreachableBlocks(Fn);

// Find the set of loop headers. We don't want to jump-thread through headers.
findLoopHeaders();
Expand All @@ -2860,7 +2820,7 @@ bool SimplifyCFG::run() {
if (simplifyBlocks()) {
// Simplifying other blocks might have resulted in unreachable
// loops.
RU.run();
removeUnreachableBlocks(Fn);

Changed = true;
}
Expand All @@ -2880,14 +2840,14 @@ bool SimplifyCFG::run() {
if (simplifyBlocks()) {
// Simplifying other blocks might have resulted in unreachable
// loops.
RU.run();
removeUnreachableBlocks(Fn);
Changed = true;
}

if (tailDuplicateObjCMethodCallSuccessorBlocks()) {
Changed = true;
if (simplifyBlocks())
RU.run();
removeUnreachableBlocks(Fn);
}

// Split all critical edges from non cond_br terminators.
Expand Down
45 changes: 45 additions & 0 deletions lib/SILOptimizer/Utils/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SILOptimizer/Utils/CFG.h"
#include "swift/SILOptimizer/Utils/Local.h"

using namespace swift;

Expand Down Expand Up @@ -968,3 +969,47 @@ bool swift::splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn,

return true;
}

namespace {
class RemoveUnreachable {
SILFunction &Fn;
llvm::SmallSet<SILBasicBlock *, 8> Visited;
public:
RemoveUnreachable(SILFunction &Fn) : Fn(Fn) { }
void visit(SILBasicBlock *BB);
bool run();
};
} // end anonymous namespace

void RemoveUnreachable::visit(SILBasicBlock *BB) {
if (!Visited.insert(BB).second)
return;

for (auto &Succ : BB->getSuccessors())
visit(Succ);
}

bool RemoveUnreachable::run() {
bool Changed = false;

// Clear each time we run so that we can run multiple times.
Visited.clear();

// Visit all blocks reachable from the entry block of the function.
visit(&*Fn.begin());

// Remove the blocks we never reached.
for (auto It = Fn.begin(), End = Fn.end(); It != End; ) {
auto *BB = &*It++;
if (!Visited.count(BB)) {
removeDeadBlock(BB);
Changed = true;
}
}

return Changed;
}

bool swift::removeUnreachableBlocks(SILFunction &Fn) {
return RemoveUnreachable(Fn).run();
}
13 changes: 13 additions & 0 deletions test/SILOptimizer/mandatory_inlining.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,16 @@ public class A {
}
}
}

// This used to crash during mandatory inlining because noreturn folding would
// create sil instructions with undef in unreachable code.
func dontCrash() {
fatalError() // expected-note {{a call to a never-returning function}}
let k = "foo" // expected-warning {{will never be executed}}
switch k {
case "bar":
return
default:
fatalError("baz \(k)")
}
}