Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1404,9 +1404,25 @@ // 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())) + if (!isa(BB.getTerminator()) && + !isa(BB.getTerminator())) return false; - return none_of(BB, instructionDoesNotReturn); + + for (auto &I : BB) { + if (instructionDoesNotReturn(I)) + return false; + + // Calls to @llvm.coro.end(..., i1 false) are themselves a return operation + // if the coroutine is retcon, so conservatively assume all are. + if (auto *CB = dyn_cast(&I)) { + if (CB->getCalledFunction() && + CB->getCalledFunction()->getIntrinsicID() == Intrinsic::coro_end && + cast(CB->getOperand(1))->isZero()) + return true; + } + } + + return isa(BB.getTerminator()); } // Set the noreturn function attribute if possible. Index: llvm/test/Transforms/FunctionAttrs/noreturn.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/noreturn.ll +++ llvm/test/Transforms/FunctionAttrs/noreturn.ll @@ -71,3 +71,20 @@ call i32 @f() noreturn ret void } + +; CHECK: Function Attrs: {{.*}}noreturn +; CHECK-NEXT: @unreachable +define void @unreachable() { + unreachable +} + +; CHECK-NOT: Function Attrs: {{.*}}noreturn +; CHECK: @coro +define void @coro() { + call token @llvm.coro.id.retcon.once(i32 0, i32 0, i8* null, i8* bitcast(void() *@coro to i8*), i8* null, i8* null) + call i1 @llvm.coro.end(i8* null, i1 false) + unreachable +} + +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)