Skip to content
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
1 change: 1 addition & 0 deletions llvm/include/llvm/Analysis/CFG.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ bool containsIrreducibleCFG(RPOTraversalT &RPOTraversal, const LoopInfoT &LI) {

return false;
}
bool canReturn(const Function &F);
} // End llvm namespace

#endif
34 changes: 34 additions & 0 deletions llvm/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,37 @@ bool llvm::isPotentiallyReachable(
return isPotentiallyReachable(
A->getParent(), B->getParent(), ExclusionSet, DT, LI);
}

static bool instructionDoesNotReturn(const Instruction &I) {
if (auto *CB = dyn_cast<CallBase>(&I))
return CB->hasFnAttr(Attribute::NoReturn);
return false;
}

// A basic block can only return if it terminates with a ReturnInst and does not
// contain calls to noreturn functions.
static bool basicBlockCanReturn(const BasicBlock &BB) {
if (!isa<ReturnInst>(BB.getTerminator()))
return false;
return none_of(BB, instructionDoesNotReturn);
}

// FIXME: this doesn't handle recursion.
bool llvm::canReturn(const Function &F) {
SmallVector<const BasicBlock *, 16> Worklist;
SmallPtrSet<const BasicBlock *, 16> Visited;

Visited.insert(&F.front());
Worklist.push_back(&F.front());

do {
const BasicBlock *BB = Worklist.pop_back_val();
if (basicBlockCanReturn(*BB))
return true;
for (const BasicBlock *Succ : successors(BB))
if (Visited.insert(Succ).second)
Worklist.push_back(Succ);
} while (!Worklist.empty());

return false;
}
35 changes: 0 additions & 35 deletions llvm/lib/Transforms/IPO/FunctionAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2090,41 +2090,6 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
Changed.insert(F);
}

static bool instructionDoesNotReturn(Instruction &I) {
if (auto *CB = dyn_cast<CallBase>(&I))
return CB->hasFnAttr(Attribute::NoReturn);
return false;
}

// A basic block can only return if it terminates with a ReturnInst and does not
// contain calls to noreturn functions.
static bool basicBlockCanReturn(BasicBlock &BB) {
if (!isa<ReturnInst>(BB.getTerminator()))
return false;
return none_of(BB, instructionDoesNotReturn);
}

// FIXME: this doesn't handle recursion.
static bool canReturn(Function &F) {
SmallVector<BasicBlock *, 16> Worklist;
SmallPtrSet<BasicBlock *, 16> Visited;

Visited.insert(&F.front());
Worklist.push_back(&F.front());

do {
BasicBlock *BB = Worklist.pop_back_val();
if (basicBlockCanReturn(*BB))
return true;
for (BasicBlock *Succ : successors(BB))
if (Visited.insert(Succ).second)
Worklist.push_back(Succ);
} while (!Worklist.empty());

return false;
}


// Set the noreturn function attribute if possible.
static void addNoReturnAttrs(const SCCNodeSet &SCCNodes,
SmallSet<Function *, 8> &Changed) {
Expand Down
Loading