Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4283,19 +4283,10 @@ if (!CS.doesNotThrow()) return false; - // Non-throwing call sites can loop infinitely, call exit/pthread_exit - // etc. and thus not return. However, LLVM already assumes that - // - // - Thread exiting actions are modeled as writes to memory invisible to - // the program. - // - // - Loops that don't have side effects (side effects are volatile/atomic - // stores and IO) always terminate (see http://llvm.org/PR965). - // Furthermore IO itself is also modeled as writes to memory invisible to - // the program. - // - // We rely on those assumptions here, and use the memory effects of the call - // target as a proxy for checking that it always returns. + // A function which doens't throw and has "willreturn" attribute will + // always return. + if (CS.hasFnAttr("willreturn")) + return true; // FIXME: This isn't aggressive enough; a call which only writes to a global // is guaranteed to return. Index: llvm/unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- llvm/unittests/Analysis/ValueTrackingTest.cpp +++ llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -464,6 +464,7 @@ "declare void @nounwind_argmemonly(i32*) nounwind argmemonly " "declare void @throws_but_readonly(i32*) readonly " "declare void @throws_but_argmemonly(i32*) argmemonly " + "declare void @nounwind_willreturn(i32*) nounwind \"willreturn\"" " " "declare void @unknown(i32*) " " " @@ -476,6 +477,7 @@ " call void @unknown(i32* %p) nounwind argmemonly " " call void @unknown(i32* %p) readonly " " call void @unknown(i32* %p) argmemonly " + " call void @nounwind_willreturn(i32* %p)" " ret void " "} "; @@ -497,6 +499,7 @@ true, // call void @unknown(i32* %p) nounwind argmemonly false, // call void @unknown(i32* %p) readonly false, // call void @unknown(i32* %p) argmemonly + true, // call void @nounwind_willreturn(i32* %p) false, // ret void };