diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 213a998d5bba2..e2f1944cee63f 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1614,6 +1614,26 @@ static bool basicBlockCanReturn(BasicBlock &BB) { 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) { @@ -1622,9 +1642,7 @@ static void addNoReturnAttrs(const SCCNodeSet &SCCNodes, F->doesNotReturn()) continue; - // The function can return if any basic blocks can return. - // FIXME: this doesn't handle recursion or unreachable blocks. - if (none_of(*F, basicBlockCanReturn)) { + if (!canReturn(*F)) { F->setDoesNotReturn(); Changed.insert(F); } diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn.ll b/llvm/test/Transforms/FunctionAttrs/noreturn.ll index eba56c9630adb..6bc1e32ed5165 100644 --- a/llvm/test/Transforms/FunctionAttrs/noreturn.ll +++ b/llvm/test/Transforms/FunctionAttrs/noreturn.ll @@ -40,9 +40,8 @@ end: ret i32 %c } -; CHECK-NOT: Function Attrs: {{.*}}noreturn +; CHECK: Function Attrs: {{.*}}noreturn ; CHECK: @caller5() -; We currently don't handle unreachable blocks. define i32 @caller5() { entry: %c = call i32 @noreturn() @@ -87,4 +86,4 @@ define void @coro() "coroutine.presplit"="1" { } declare token @llvm.coro.id.retcon.once(i32 %size, i32 %align, i8* %buffer, i8* %prototype, i8* %alloc, i8* %free) -declare i1 @llvm.coro.end(i8*, i1) \ No newline at end of file +declare i1 @llvm.coro.end(i8*, i1)