diff --git a/llvm/include/llvm/Analysis/CFG.h b/llvm/include/llvm/Analysis/CFG.h index 23bc10a4a9d1b..8451e88146d7c 100644 --- a/llvm/include/llvm/Analysis/CFG.h +++ b/llvm/include/llvm/Analysis/CFG.h @@ -174,6 +174,7 @@ bool containsIrreducibleCFG(RPOTraversalT &RPOTraversal, const LoopInfoT &LI) { return false; } +bool canReturn(const Function &F); } // End llvm namespace #endif diff --git a/llvm/lib/Analysis/CFG.cpp b/llvm/lib/Analysis/CFG.cpp index 841b835052380..8ced4a901557d 100644 --- a/llvm/lib/Analysis/CFG.cpp +++ b/llvm/lib/Analysis/CFG.cpp @@ -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(&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(BB.getTerminator())) + return false; + return none_of(BB, instructionDoesNotReturn); +} + +// FIXME: this doesn't handle recursion. +bool llvm::canReturn(const Function &F) { + SmallVector Worklist; + SmallPtrSet 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; +} diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index ef7989507c89f..bbfed2ac2c090 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -2090,41 +2090,6 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes, Changed.insert(F); } -static bool instructionDoesNotReturn(Instruction &I) { - if (auto *CB = dyn_cast(&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(BB.getTerminator())) - return false; - return none_of(BB, instructionDoesNotReturn); -} - -// FIXME: this doesn't handle recursion. -static bool canReturn(Function &F) { - SmallVector Worklist; - SmallPtrSet 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 &Changed) {